aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2015-03-21 05:33:40 +0800
committerFelix Lange <fjl@twurst.com>2015-03-21 05:33:40 +0800
commitb41185a68f2ec8c492a7dbec1a6bf65f29b0843a (patch)
tree309fe50a122cd1db099381e8961349d842fac765
parent28ddc16a9b5779b6b31036e8248ed8457de7b443 (diff)
downloaddexon-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.go7
-rw-r--r--rlp/decode_test.go22
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)},