forked from cerc-io/plugeth
rlp: fix panic in decodeList on go 1.4+
The documentation for reflect.Value.Index states that it will panic for out-of-bounds indices. Since go 1.4, it actually panics.
This commit is contained in:
parent
93e858f88e
commit
c084a7daa5
@ -154,8 +154,6 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxInt = int(^uint(0) >> 1)
|
|
||||||
|
|
||||||
func makeListDecoder(typ reflect.Type) (decoder, error) {
|
func makeListDecoder(typ reflect.Type) (decoder, error) {
|
||||||
etype := typ.Elem()
|
etype := typ.Elem()
|
||||||
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
|
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
|
||||||
@ -169,42 +167,29 @@ func makeListDecoder(typ reflect.Type) (decoder, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var maxLen = maxInt
|
|
||||||
if typ.Kind() == reflect.Array {
|
if typ.Kind() == reflect.Array {
|
||||||
maxLen = typ.Len()
|
return func(s *Stream, val reflect.Value) error {
|
||||||
|
return decodeListArray(s, val, etypeinfo.decoder)
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
dec := func(s *Stream, val reflect.Value) error {
|
return func(s *Stream, val reflect.Value) error {
|
||||||
return decodeList(s, val, etypeinfo.decoder, maxLen)
|
return decodeListSlice(s, val, etypeinfo.decoder)
|
||||||
}
|
}, nil
|
||||||
return dec, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeList decodes RLP list elements into slices and arrays.
|
func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||||
//
|
|
||||||
// The approach here is stolen from package json, although we differ
|
|
||||||
// in the semantics for arrays. package json discards remaining
|
|
||||||
// elements that would not fit into the array. We generate an error in
|
|
||||||
// this case because we'd be losing information.
|
|
||||||
func decodeList(s *Stream, val reflect.Value, elemdec decoder, maxelem int) error {
|
|
||||||
size, err := s.List()
|
size, err := s.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
if val.Kind() == reflect.Slice {
|
|
||||||
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
|
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
|
||||||
} else {
|
|
||||||
zero(val, 0)
|
|
||||||
}
|
|
||||||
return s.ListEnd()
|
return s.ListEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for {
|
for ; ; i++ {
|
||||||
if i > maxelem {
|
|
||||||
return decodeError{"input list has too many elements", val.Type()}
|
|
||||||
}
|
|
||||||
if val.Kind() == reflect.Slice {
|
|
||||||
// grow slice if necessary
|
// grow slice if necessary
|
||||||
if i >= val.Cap() {
|
if i >= val.Cap() {
|
||||||
newcap := val.Cap() + val.Cap()/2
|
newcap := val.Cap() + val.Cap()/2
|
||||||
@ -218,33 +203,60 @@ func decodeList(s *Stream, val reflect.Value, elemdec decoder, maxelem int) erro
|
|||||||
if i >= val.Len() {
|
if i >= val.Len() {
|
||||||
val.SetLen(i + 1)
|
val.SetLen(i + 1)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// decode into element
|
// decode into element
|
||||||
if err := elemdec(s, val.Index(i)); err == EOL {
|
if err := elemdec(s, val.Index(i)); err == EOL {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
if i < val.Len() {
|
if i < val.Len() {
|
||||||
if val.Kind() == reflect.Array {
|
|
||||||
// zero the rest of the array.
|
|
||||||
zero(val, i)
|
|
||||||
} else {
|
|
||||||
val.SetLen(i)
|
val.SetLen(i)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return s.ListEnd()
|
return s.ListEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeListArray(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||||
|
size, err := s.List()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if size == 0 {
|
||||||
|
zero(val, 0)
|
||||||
|
return s.ListEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The approach here is stolen from package json, although we differ
|
||||||
|
// in the semantics for arrays. package json discards remaining
|
||||||
|
// elements that would not fit into the array. We generate an error in
|
||||||
|
// this case because we'd be losing information.
|
||||||
|
vlen := val.Len()
|
||||||
|
i := 0
|
||||||
|
for ; i < vlen; i++ {
|
||||||
|
if err := elemdec(s, val.Index(i)); err == EOL {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i == vlen {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i < vlen {
|
||||||
|
zero(val, i)
|
||||||
|
}
|
||||||
|
if err = s.ListEnd(); err == errNotAtEOL {
|
||||||
|
return decodeError{"input list has too many elements", val.Type()}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func decodeByteSlice(s *Stream, val reflect.Value) error {
|
func decodeByteSlice(s *Stream, val reflect.Value) error {
|
||||||
kind, _, err := s.Kind()
|
kind, _, err := s.Kind()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if kind == List {
|
if kind == List {
|
||||||
return decodeList(s, val, decodeUint, maxInt)
|
return decodeListSlice(s, val, decodeUint)
|
||||||
}
|
}
|
||||||
b, err := s.Bytes()
|
b, err := s.Bytes()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -276,14 +288,15 @@ func decodeByteArray(s *Stream, val reflect.Value) error {
|
|||||||
}
|
}
|
||||||
zero(val, int(size))
|
zero(val, int(size))
|
||||||
case List:
|
case List:
|
||||||
return decodeList(s, val, decodeUint, val.Len())
|
return decodeListArray(s, val, decodeUint)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func zero(val reflect.Value, start int) {
|
func zero(val reflect.Value, start int) {
|
||||||
z := reflect.Zero(val.Type().Elem())
|
z := reflect.Zero(val.Type().Elem())
|
||||||
for i := start; i < val.Len(); i++ {
|
end := val.Len()
|
||||||
|
for i := start; i < end; i++ {
|
||||||
val.Index(i).Set(z)
|
val.Index(i).Set(z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,7 +371,7 @@ func decodeInterface(s *Stream, val reflect.Value) error {
|
|||||||
}
|
}
|
||||||
if kind == List {
|
if kind == List {
|
||||||
slice := reflect.New(ifsliceType).Elem()
|
slice := reflect.New(ifsliceType).Elem()
|
||||||
if err := decodeList(s, slice, decodeInterface, maxInt); err != nil {
|
if err := decodeListSlice(s, slice, decodeInterface); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
val.Set(slice)
|
val.Set(slice)
|
||||||
|
Loading…
Reference in New Issue
Block a user