Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RLP: remove support for signed ints and other fixes #202

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 92 additions & 69 deletions rlp/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type Decoder interface {
// To decode into a Go string, the input must be an RLP string. The
// bytes are taken as-is and will not necessarily be valid UTF-8.
//
// To decode into an integer type, the input must also be an RLP
// To decode into an unsigned integer type, the input must also be an RLP
// string. The bytes are interpreted as a big endian representation of
// the integer. If the RLP string is larger than the bit size of the
// type, Decode will return an error. Decode also supports *big.Int.
Expand All @@ -66,8 +66,9 @@ type Decoder interface {
// []interface{}, for RLP lists
// []byte, for RLP strings
//
// Non-empty interface types are not supported, nor are bool, float32,
// float64, maps, channel types and functions.
// Non-empty interface types are not supported, nor are booleans,
// signed integers, floating point numbers, maps, channels and
// functions.
func Decode(r io.Reader, val interface{}) error {
return NewStream(r).Decode(val)
}
Expand All @@ -81,28 +82,37 @@ func (err decodeError) Error() string {
return fmt.Sprintf("rlp: %s for %v", err.msg, err.typ)
}

func makeNumDecoder(typ reflect.Type) decoder {
var (
decoderInterface = reflect.TypeOf(new(Decoder)).Elem()
bigInt = reflect.TypeOf(big.Int{})
)

func makeDecoder(typ reflect.Type) (dec decoder, err error) {
kind := typ.Kind()
switch {
case kind <= reflect.Int64:
return decodeInt
case kind <= reflect.Uint64:
return decodeUint
case typ.Implements(decoderInterface):
return decodeDecoder, nil
case kind != reflect.Ptr && reflect.PtrTo(typ).Implements(decoderInterface):
return decodeDecoderNoPtr, nil
case typ.AssignableTo(reflect.PtrTo(bigInt)):
return decodeBigInt, nil
case typ.AssignableTo(bigInt):
return decodeBigIntNoPtr, nil
case isUint(kind):
return decodeUint, nil
case kind == reflect.String:
return decodeString, nil
case kind == reflect.Slice || kind == reflect.Array:
return makeListDecoder(typ)
case kind == reflect.Struct:
return makeStructDecoder(typ)
case kind == reflect.Ptr:
return makePtrDecoder(typ)
case kind == reflect.Interface && typ.NumMethod() == 0:
return decodeInterface, nil
default:
panic("fallthrough")
}
}

func decodeInt(s *Stream, val reflect.Value) error {
typ := val.Type()
num, err := s.uint(typ.Bits())
if err == errUintOverflow {
return decodeError{"input string too long", typ}
} else if err != nil {
return err
return nil, fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
}
val.SetInt(int64(num))
return nil
}

func decodeUint(s *Stream, val reflect.Value) error {
Expand Down Expand Up @@ -144,8 +154,6 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
return nil
}

const maxInt = int(^uint(0) >> 1)

func makeListDecoder(typ reflect.Type) (decoder, error) {
etype := typ.Elem()
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
Expand All @@ -159,82 +167,96 @@ func makeListDecoder(typ reflect.Type) (decoder, error) {
if err != nil {
return nil, err
}
var maxLen = maxInt

if typ.Kind() == reflect.Array {
maxLen = typ.Len()
}
dec := func(s *Stream, val reflect.Value) error {
return decodeList(s, val, etypeinfo.decoder, maxLen)
return func(s *Stream, val reflect.Value) error {
return decodeListArray(s, val, etypeinfo.decoder)
}, nil
}
return dec, nil
return func(s *Stream, val reflect.Value) error {
return decodeListSlice(s, val, etypeinfo.decoder)
}, nil
}

// decodeList decodes RLP list elements into slices and arrays.
//
// 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 {
func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error {
size, err := s.List()
if err != nil {
return err
}
if size == 0 {
if val.Kind() == reflect.Slice {
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
} else {
zero(val, 0)
}
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
return s.ListEnd()
}

i := 0
for {
if i > maxelem {
return decodeError{"input list has too many elements", val.Type()}
}
if val.Kind() == reflect.Slice {
// grow slice if necessary
if i >= val.Cap() {
newcap := val.Cap() + val.Cap()/2
if newcap < 4 {
newcap = 4
}
newv := reflect.MakeSlice(val.Type(), val.Len(), newcap)
reflect.Copy(newv, val)
val.Set(newv)
}
if i >= val.Len() {
val.SetLen(i + 1)
for ; ; i++ {
// grow slice if necessary
if i >= val.Cap() {
newcap := val.Cap() + val.Cap()/2
if newcap < 4 {
newcap = 4
}
newv := reflect.MakeSlice(val.Type(), val.Len(), newcap)
reflect.Copy(newv, val)
val.Set(newv)
}
if i >= val.Len() {
val.SetLen(i + 1)
}
// decode into element
if err := elemdec(s, val.Index(i)); err == EOL {
break
} else if err != nil {
return err
}
i++
}
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()
}

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 {
kind, _, err := s.Kind()
if err != nil {
return err
}
if kind == List {
return decodeList(s, val, decodeUint, maxInt)
return decodeListSlice(s, val, decodeUint)
}
b, err := s.Bytes()
if err == nil {
Expand Down Expand Up @@ -266,14 +288,15 @@ func decodeByteArray(s *Stream, val reflect.Value) error {
}
zero(val, int(size))
case List:
return decodeList(s, val, decodeUint, val.Len())
return decodeListArray(s, val, decodeUint)
}
return nil
}

func zero(val reflect.Value, start int) {
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)
}
}
Expand Down Expand Up @@ -348,7 +371,7 @@ func decodeInterface(s *Stream, val reflect.Value) error {
}
if kind == List {
slice := reflect.New(ifsliceType).Elem()
if err := decodeList(s, slice, decodeInterface, maxInt); err != nil {
if err := decodeListSlice(s, slice, decodeInterface); err != nil {
return err
}
val.Set(slice)
Expand Down
42 changes: 21 additions & 21 deletions rlp/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestDecodeErrors(t *testing.T) {
t.Errorf("Decode(r, new(chan bool)) error mismatch, got %q, want %q", err, expectErr)
}

if err := Decode(r, new(int)); err != io.EOF {
if err := Decode(r, new(uint)); err != io.EOF {
t.Errorf("Decode(r, new(int)) error mismatch, got %q, want %q", err, io.EOF)
}
}
Expand All @@ -184,12 +184,12 @@ type decodeTest struct {
}

type simplestruct struct {
A int
A uint
B string
}

type recstruct struct {
I int
I uint
Child *recstruct
}

Expand All @@ -202,7 +202,7 @@ var (

var (
sharedByteArray [5]byte
sharedPtr = new(*int)
sharedPtr = new(*uint)
)

var decodeTests = []decodeTest{
Expand All @@ -217,13 +217,13 @@ var decodeTests = []decodeTest{
{input: "C0", ptr: new(uint32), error: ErrExpectedString.Error()},

// slices
{input: "C0", ptr: new([]int), value: []int{}},
{input: "C80102030405060708", ptr: new([]int), value: []int{1, 2, 3, 4, 5, 6, 7, 8}},
{input: "C0", ptr: new([]uint), value: []uint{}},
{input: "C80102030405060708", ptr: new([]uint), value: []uint{1, 2, 3, 4, 5, 6, 7, 8}},

// arrays
{input: "C0", ptr: new([5]int), value: [5]int{}},
{input: "C50102030405", ptr: new([5]int), value: [5]int{1, 2, 3, 4, 5}},
{input: "C6010203040506", ptr: new([5]int), error: "rlp: input list has too many elements for [5]int"},
{input: "C0", ptr: new([5]uint), value: [5]uint{}},
{input: "C50102030405", ptr: new([5]uint), value: [5]uint{1, 2, 3, 4, 5}},
{input: "C6010203040506", ptr: new([5]uint), error: "rlp: input list has too many elements for [5]uint"},

// byte slices
{input: "01", ptr: new([]byte), value: []byte{1}},
Expand Down Expand Up @@ -280,17 +280,17 @@ var decodeTests = []decodeTest{
},

// pointers
{input: "00", ptr: new(*int), value: (*int)(nil)},
{input: "80", ptr: new(*int), value: (*int)(nil)},
{input: "C0", ptr: new(*int), value: (*int)(nil)},
{input: "07", ptr: new(*int), value: intp(7)},
{input: "8108", ptr: new(*int), value: intp(8)},
{input: "C109", ptr: new(*[]int), value: &[]int{9}},
{input: "00", ptr: new(*uint), value: (*uint)(nil)},
{input: "80", ptr: new(*uint), value: (*uint)(nil)},
{input: "C0", ptr: new(*uint), value: (*uint)(nil)},
{input: "07", ptr: new(*uint), value: uintp(7)},
{input: "8108", ptr: new(*uint), value: uintp(8)},
{input: "C109", ptr: new(*[]uint), value: &[]uint{9}},
{input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}},

// pointer should be reset to nil
{input: "05", ptr: sharedPtr, value: intp(5)},
{input: "80", ptr: sharedPtr, value: (*int)(nil)},
{input: "05", ptr: sharedPtr, value: uintp(5)},
{input: "80", ptr: sharedPtr, value: (*uint)(nil)},

// interface{}
{input: "00", ptr: new(interface{}), value: []byte{0}},
Expand All @@ -301,7 +301,7 @@ var decodeTests = []decodeTest{
{input: "C50183040404", ptr: new(interface{}), value: []interface{}{[]byte{1}, []byte{4, 4, 4}}},
}

func intp(i int) *int { return &i }
func uintp(i uint) *uint { return &i }

func runTests(t *testing.T, decode func([]byte, interface{}) error) {
for i, test := range decodeTests {
Expand Down Expand Up @@ -434,8 +434,8 @@ func ExampleDecode() {
input, _ := hex.DecodeString("C90A1486666F6F626172")

type example struct {
A, B int
private int // private fields are ignored
A, B uint
private uint // private fields are ignored
String string
}

Expand All @@ -447,7 +447,7 @@ func ExampleDecode() {
fmt.Printf("Decoded value: %#v\n", s)
}
// Output:
// Decoded value: rlp.example{A:10, B:20, private:0, String:"foobar"}
// Decoded value: rlp.example{A:0xa, B:0x14, private:0x0, String:"foobar"}
}

func ExampleStream() {
Expand Down
Loading