fix: math: fix Uint.Unmarshal's lack of negative value checking (#11996)
This change adds a negative value check to Uint.Unmarshal, which coincidentally is fixed by refactoring for code reuse. While here, added tests to ensure we don't regress. Fixes #11995
This commit is contained in:
parent
89c727cb78
commit
54d764b9a8
12
math/uint.go
12
math/uint.go
|
@ -190,11 +190,8 @@ func (u *Uint) Unmarshal(data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.i.BitLen() > MaxBitLen {
|
// Finally check for overflow.
|
||||||
return fmt.Errorf("integer out of range; got: %d, max: %d", u.i.BitLen(), MaxBitLen)
|
return UintOverflow(u.i)
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size implements the gogo proto custom type interface.
|
// Size implements the gogo proto custom type interface.
|
||||||
|
@ -213,8 +210,9 @@ func UintOverflow(i *big.Int) error {
|
||||||
if i.Sign() < 0 {
|
if i.Sign() < 0 {
|
||||||
return errors.New("non-positive integer")
|
return errors.New("non-positive integer")
|
||||||
}
|
}
|
||||||
if i.BitLen() > 256 {
|
|
||||||
return fmt.Errorf("bit length %d greater than 256", i.BitLen())
|
if g, w := i.BitLen(), MaxBitLen; g > w {
|
||||||
|
return fmt.Errorf("integer out of range; got: %d, max: %d", g, w)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
sdkmath "cosmossdk.io/math"
|
sdkmath "cosmossdk.io/math"
|
||||||
|
@ -300,6 +301,7 @@ func TestRoundTripMarshalToUint(t *testing.T) {
|
||||||
1<<63 - 1,
|
1<<63 - 1,
|
||||||
1<<32 - 7,
|
1<<32 - 7,
|
||||||
1<<22 - 8,
|
1<<22 - 8,
|
||||||
|
math.MaxUint64,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
|
@ -323,3 +325,39 @@ func TestRoundTripMarshalToUint(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWeakUnmarshalNegativeSign(t *testing.T) {
|
||||||
|
neg10, _ := new(big.Int).SetString("-10", 0)
|
||||||
|
blob, err := neg10.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := new(sdkmath.Uint)
|
||||||
|
err = ui.Unmarshal(blob)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Failed to catch the negative value")
|
||||||
|
}
|
||||||
|
if errStr := err.Error(); !strings.Contains(errStr, "non-positive") {
|
||||||
|
t.Fatalf("negative value not reported, got instead %q", errStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeakUnmarshalOverflow(t *testing.T) {
|
||||||
|
exp := new(big.Int).SetUint64(256)
|
||||||
|
pos10, _ := new(big.Int).SetString("10", 0)
|
||||||
|
exp10Pow256 := new(big.Int).Exp(pos10, exp, nil)
|
||||||
|
blob, err := exp10Pow256.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui := new(sdkmath.Uint)
|
||||||
|
err = ui.Unmarshal(blob)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Failed to catch the overflowed value")
|
||||||
|
}
|
||||||
|
if errStr := err.Error(); !strings.Contains(errStr, "out of range") {
|
||||||
|
t.Fatalf("out of range value not reported, got instead %q", errStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue