diff options
author | Felix Lange <fjl@twurst.com> | 2015-03-21 05:33:40 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2015-03-21 05:33:40 +0800 |
commit | b41185a68f2ec8c492a7dbec1a6bf65f29b0843a (patch) | |
tree | 309fe50a122cd1db099381e8961349d842fac765 | |
parent | 28ddc16a9b5779b6b31036e8248ed8457de7b443 (diff) | |
download | dexon-b41185a68f2ec8c492a7dbec1a6bf65f29b0843a.tar.gz dexon-b41185a68f2ec8c492a7dbec1a6bf65f29b0843a.tar.zst dexon-b41185a68f2ec8c492a7dbec1a6bf65f29b0843a.zip |
rlp: fix nil pointer decoding
The generic pointer decoder did not advance the input position
for empty values. This can lead to strange issues and even
infinite loops.
-rw-r--r-- | rlp/decode.go | 7 | ||||
-rw-r--r-- | rlp/decode_test.go | 22 |
2 files changed, 27 insertions, 2 deletions
diff --git a/rlp/decode.go b/rlp/decode.go index 6d7e670c2..0e99d9caa 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -367,7 +367,12 @@ func makePtrDecoder(typ reflect.Type) (decoder, error) { dec := func(s *Stream, val reflect.Value) (err error) { _, size, err := s.Kind() if err != nil || size == 0 && s.byteval == 0 { - val.Set(reflect.Zero(typ)) // set to nil + // rearm s.Kind. This is important because the input + // position must advance to the next value even though + // we don't read anything. + s.kind = -1 + // set the pointer to nil. + val.Set(reflect.Zero(typ)) return err } newval := val diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 9f66840b1..0f034d5d8 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -39,7 +39,7 @@ func TestStreamKind(t *testing.T) { s := NewStream(bytes.NewReader(unhex(test.input))) kind, len, err := s.Kind() if err != nil { - t.Errorf("test %d: Type returned error: %v", i, err) + t.Errorf("test %d: Kind returned error: %v", i, err) continue } if kind != test.wantKind { @@ -93,6 +93,23 @@ func TestStreamErrors(t *testing.T) { {"C3C2010201", calls{"List", "List", "Uint", "Uint", "ListEnd", "Uint"}, EOL}, {"00", calls{"ListEnd"}, errNotInList}, {"C40102", calls{"List", "Uint", "ListEnd"}, errNotAtEOL}, + + // This test verifies that the input position is advanced + // correctly when calling Bytes for empty strings. Kind can be called + // any number of times in between and doesn't advance. + {"C3808080", calls{ + "List", // enter the list + "Bytes", // past first element + + "Kind", "Kind", "Kind", // this shouldn't advance + + "Bytes", // past second element + + "Kind", "Kind", // can't hurt to try + + "Bytes", // past final element + "Bytes", // this one should fail + }, EOL}, } testfor: @@ -314,6 +331,9 @@ var decodeTests = []decodeTest{ {input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, {input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, + // check that input position is advanced also empty values. + {input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}}, + // pointer should be reset to nil {input: "05", ptr: sharedPtr, value: uintp(5)}, {input: "80", ptr: sharedPtr, value: (*uint)(nil)}, |