Skip to content

Commit

Permalink
conversion: fix unmarshalling overflow (holiman#185)
Browse files Browse the repository at this point in the history
The json-unmarshalling from decimal form inorrectly invoked fromDecimal,
instead of SetFromDecimal. The former assumes that the input has already
been validated, and thus does not throw errors on overflow.

Closes holiman#184
  • Loading branch information
holiman authored Oct 2, 2024
1 parent ce90883 commit b07109b
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
4 changes: 2 additions & 2 deletions conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func (z *Int) UnmarshalText(input []byte) error {
if len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') {
return z.fromHex(string(input))
}
return z.fromDecimal(string(input))
return z.SetFromDecimal(string(input))
}

// SetFromBig converts a big.Int to Int and sets the value to z.
Expand Down Expand Up @@ -712,7 +712,7 @@ func (z *Int) MarshalJSON() ([]byte, error) {
func (z *Int) UnmarshalJSON(input []byte) error {
if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' {
// if not quoted, it must be decimal
return z.fromDecimal(string(input))
return z.SetFromDecimal(string(input))
}
return z.UnmarshalText(input[1 : len(input)-1])
}
Expand Down
28 changes: 28 additions & 0 deletions conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,34 @@ func TestEnDecode(t *testing.T) {
}
}

func TestMarshallingErrors(t *testing.T) {
var check = func(repr string) string {
a := new(Int)
if err := json.Unmarshal([]byte(repr), a); err != nil {
return fmt.Sprintf("error: %v", err.Error())
}
return a.String()
}

for i, tc := range []string{
`0x1000000000000000000000000000000000000000000000000000000000000000`,
`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`,
`0x10000000000000000000000000000000000000000000000000000000000000000`,
`0x10000000000000000000000000000000000000000000000000000000000000001`,
`0x111110000000000000000000000000000000000000000000000000000000000000001`,
} {
reference, ok := new(big.Int).SetString(tc, 0)
if !ok {
t.Fatalf("test %d: not ok input %q", i, tc)
}
haveHex := check(fmt.Sprintf(`"%#x"`, reference))
haveDec := check(fmt.Sprintf(`"%#d"`, reference))
if haveHex != haveDec {
t.Fatalf("test %d: hex unmarshal != dec unmarshal, \nhex -> %q\ndec -> %q\n", i, haveHex, haveDec)
}
}
}

func TestNil(t *testing.T) {
a := NewInt(1337)
if err := a.Scan(nil); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ var multipliers = [5]*Int{
// fromDecimal is a helper function to only ever be called via SetFromDecimal
// this function takes a string and chunks it up, calling ParseUint on it up to 5 times
// these chunks are then multiplied by the proper power of 10, then added together.
// Note: this method assumes that some basic validity-checks have already been performed
// on the input 'bs'. See SetFromDecimal.
func (z *Int) fromDecimal(bs string) error {
// first clear the input
z.Clear()
Expand Down

0 comments on commit b07109b

Please sign in to comment.