mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
Add static analysis for unsafe uint casting (#10318)
* Add static analysis for unsafe uint casting * Fix violations of uintcast * go mod tidy * Add exclusion to nogo for darwin build * Add test for math.Int * Move some things to const so they are assured not to exceed int64 * Self review * lint * fix tests * fix test * Add init check for non 64 bit OS * Move new deps from WORKSPACE to deps.bzl * fix bazel build for go analysis runs * Update BUILD.bazel Remove TODO * add math.AddInt method * Add new test casts * Add case where builtin functions and declared functions are covered * Fix new findings * cleanup Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: Nishant Das <nishdas93@gmail.com>
This commit is contained in:
@@ -9,6 +9,19 @@ import (
|
||||
"github.com/thomaso-mirodin/intmath/u64"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// The Int function assumes that the operating system is 64 bit. In any case, Ethereum
|
||||
// consensus layer uses 64 bit values almost exclusively so 64 bit OS requirement should
|
||||
// already be established. This panic is a strict fail fast feedback to alert 32 bit users
|
||||
// that they are not supported.
|
||||
if stdmath.MaxUint < stdmath.MaxUint64 {
|
||||
panic("Prysm is only supported on 64 bit OS")
|
||||
}
|
||||
}
|
||||
|
||||
// ErrOverflow occurs when an operation exceeds max or minimum values.
|
||||
var ErrOverflow = errors.New("integer overflow")
|
||||
|
||||
// Common square root values.
|
||||
var squareRootTable = map[uint64]uint64{
|
||||
4: 2,
|
||||
@@ -121,3 +134,28 @@ func Sub64(a, b uint64) (uint64, error) {
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Int returns the integer value of the uint64 argument. If there is an overlow, then an error is
|
||||
// returned.
|
||||
func Int(u uint64) (int, error) {
|
||||
if u > stdmath.MaxInt {
|
||||
return 0, ErrOverflow
|
||||
}
|
||||
return int(u), nil // lint:ignore uintcast -- This is the preferred method of casting uint64 to int.
|
||||
}
|
||||
|
||||
// AddInt adds two or more integers and checks for integer overflows.
|
||||
func AddInt(i ...int) (int, error) {
|
||||
var sum int
|
||||
for _, ii := range i {
|
||||
if ii > 0 && sum > stdmath.MaxInt-ii {
|
||||
return 0, ErrOverflow
|
||||
} else if ii < 0 && sum < stdmath.MinInt-ii {
|
||||
return 0, ErrOverflow
|
||||
}
|
||||
|
||||
sum += ii
|
||||
|
||||
}
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package math_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
stdmath "math"
|
||||
"testing"
|
||||
|
||||
@@ -366,3 +367,87 @@ func TestMath_Sub64(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
tests := []struct {
|
||||
arg uint64
|
||||
want int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
arg: 0,
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
arg: 10000000,
|
||||
want: 10000000,
|
||||
},
|
||||
{
|
||||
arg: stdmath.MaxInt64,
|
||||
want: stdmath.MaxInt64,
|
||||
},
|
||||
{
|
||||
arg: stdmath.MaxInt64 + 1,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(fmt.Sprint(tt.arg), func(t *testing.T) {
|
||||
got, err := math.Int(tt.arg)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Int() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Int() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddInt(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []int
|
||||
want int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no overflow",
|
||||
args: []int{1, 2, 3, 4, 5},
|
||||
want: 15,
|
||||
},
|
||||
{
|
||||
name: "overflow",
|
||||
args: []int{1, stdmath.MaxInt},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "underflow",
|
||||
args: []int{-1, stdmath.MinInt},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "max int",
|
||||
args: []int{1, stdmath.MaxInt - 1},
|
||||
want: stdmath.MaxInt,
|
||||
},
|
||||
{
|
||||
name: "min int",
|
||||
args: []int{-1, stdmath.MinInt + 1},
|
||||
want: stdmath.MinInt,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := math.AddInt(tt.args...)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("AddInt() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("AddInt() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user