@@ -29,6 +29,7 @@ package abi
2929import (
3030 "encoding/binary"
3131 "fmt"
32+ "math"
3233 "math/big"
3334 "reflect"
3435
@@ -43,43 +44,72 @@ var (
4344)
4445
4546// ReadInteger reads the integer based on its kind and returns the appropriate value.
46- func ReadInteger (typ Type , b []byte ) interface {} {
47+ func ReadInteger (typ Type , b []byte ) (interface {}, error ) {
48+ ret := new (big.Int ).SetBytes (b )
49+
4750 if typ .T == UintTy {
51+ u64 , isu64 := ret .Uint64 (), ret .IsUint64 ()
4852 switch typ .Size {
4953 case 8 :
50- return b [len (b )- 1 ]
54+ if ! isu64 || u64 > math .MaxUint8 {
55+ return nil , errBadUint8
56+ }
57+ return byte (u64 ), nil
5158 case 16 :
52- return binary .BigEndian .Uint16 (b [len (b )- 2 :])
59+ if ! isu64 || u64 > math .MaxUint16 {
60+ return nil , errBadUint16
61+ }
62+ return uint16 (u64 ), nil
5363 case 32 :
54- return binary .BigEndian .Uint32 (b [len (b )- 4 :])
64+ if ! isu64 || u64 > math .MaxUint32 {
65+ return nil , errBadUint32
66+ }
67+ return uint32 (u64 ), nil
5568 case 64 :
56- return binary .BigEndian .Uint64 (b [len (b )- 8 :])
69+ if ! isu64 {
70+ return nil , errBadUint64
71+ }
72+ return u64 , nil
5773 default :
5874 // the only case left for unsigned integer is uint256.
59- return new (big. Int ). SetBytes ( b )
75+ return ret , nil
6076 }
6177 }
78+
79+ // big.SetBytes can't tell if a number is negative or positive in itself.
80+ // On EVM, if the returned number > max int256, it is negative.
81+ // A number is > max int256 if the bit at position 255 is set.
82+ if ret .Bit (255 ) == 1 {
83+ ret .Add (MaxUint256 , new (big.Int ).Neg (ret ))
84+ ret .Add (ret , common .Big1 )
85+ ret .Neg (ret )
86+ }
87+ i64 , isi64 := ret .Int64 (), ret .IsInt64 ()
6288 switch typ .Size {
6389 case 8 :
64- return int8 (b [len (b )- 1 ])
90+ if ! isi64 || i64 < math .MinInt8 || i64 > math .MaxInt8 {
91+ return nil , errBadInt8
92+ }
93+ return int8 (i64 ), nil
6594 case 16 :
66- return int16 (binary .BigEndian .Uint16 (b [len (b )- 2 :]))
95+ if ! isi64 || i64 < math .MinInt16 || i64 > math .MaxInt16 {
96+ return nil , errBadInt16
97+ }
98+ return int16 (i64 ), nil
6799 case 32 :
68- return int32 (binary .BigEndian .Uint32 (b [len (b )- 4 :]))
100+ if ! isi64 || i64 < math .MinInt32 || i64 > math .MaxInt32 {
101+ return nil , errBadInt32
102+ }
103+ return int32 (i64 ), nil
69104 case 64 :
70- return int64 (binary .BigEndian .Uint64 (b [len (b )- 8 :]))
105+ if ! isi64 {
106+ return nil , errBadInt64
107+ }
108+ return i64 , nil
71109 default :
72110 // the only case left for integer is int256
73- // big.SetBytes can't tell if a number is negative or positive in itself.
74- // On EVM, if the returned number > max int256, it is negative.
75- // A number is > max int256 if the bit at position 255 is set.
76- ret := new (big.Int ).SetBytes (b )
77- if ret .Bit (255 ) == 1 {
78- ret .Add (MaxUint256 , new (big.Int ).Neg (ret ))
79- ret .Add (ret , common .Big1 )
80- ret .Neg (ret )
81- }
82- return ret
111+
112+ return ret , nil
83113 }
84114}
85115
@@ -133,7 +163,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
133163 return nil , fmt .Errorf ("cannot marshal input to array, size is negative (%d)" , size )
134164 }
135165 if start + 32 * size > len (output ) {
136- return nil , fmt .Errorf ("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)" , len (output ), start + 32 * size )
166+ return nil , fmt .Errorf ("abi: cannot marshal into go array: offset %d would go over slice boundary (len=%d)" , len (output ), start + 32 * size )
137167 }
138168
139169 // this value will become our slice or our array, depending on the type
@@ -244,7 +274,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
244274 case StringTy : // variable arrays are written at the end of the return bytes
245275 return string (output [begin : begin + length ]), nil
246276 case IntTy , UintTy :
247- return ReadInteger (t , returnOutput ), nil
277+ return ReadInteger (t , returnOutput )
248278 case BoolTy :
249279 return readBool (returnOutput )
250280 case AddressTy :
0 commit comments