From 6abf8ef78f1474fdeb7a6a6ce084bf994cc055f2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 Jan 2015 17:10:42 +0100 Subject: Merge --- rlp/decode.go | 57 +++++++++++++++++++++++++++++++++++++----------------- rlp/decode_test.go | 38 +++++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 23 deletions(-) (limited to 'rlp') diff --git a/rlp/decode.go b/rlp/decode.go index 712d9fcf1..a2bd04285 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -76,22 +76,37 @@ func Decode(r io.Reader, val interface{}) error { type decodeError struct { msg string typ reflect.Type + ctx []string } -func (err decodeError) Error() string { - return fmt.Sprintf("rlp: %s for %v", err.msg, err.typ) +func (err *decodeError) Error() string { + ctx := "" + if len(err.ctx) > 0 { + ctx = ", decoding into " + for i := len(err.ctx) - 1; i >= 0; i-- { + ctx += err.ctx[i] + } + } + return fmt.Sprintf("rlp: %s for %v%s", err.msg, err.typ, ctx) } func wrapStreamError(err error, typ reflect.Type) error { switch err { case ErrExpectedList: - return decodeError{"expected input list", typ} + return &decodeError{msg: "expected input list", typ: typ} case ErrExpectedString: - return decodeError{"expected input string or byte", typ} + return &decodeError{msg: "expected input string or byte", typ: typ} case errUintOverflow: - return decodeError{"input string too long", typ} + return &decodeError{msg: "input string too long", typ: typ} case errNotAtEOL: - return decodeError{"input list has too many elements", typ} + return &decodeError{msg: "input list has too many elements", typ: typ} + } + return err +} + +func addErrorContext(err error, ctx string) error { + if decErr, ok := err.(*decodeError); ok { + decErr.ctx = append(decErr.ctx, ctx) } return err } @@ -180,13 +195,13 @@ func makeListDecoder(typ reflect.Type) (decoder, error) { return nil, err } - if typ.Kind() == reflect.Array { - return func(s *Stream, val reflect.Value) error { - return decodeListArray(s, val, etypeinfo.decoder) - }, nil - } + isArray := typ.Kind() == reflect.Array return func(s *Stream, val reflect.Value) error { - return decodeListSlice(s, val, etypeinfo.decoder) + if isArray { + return decodeListArray(s, val, etypeinfo.decoder) + } else { + return decodeListSlice(s, val, etypeinfo.decoder) + } }, nil } @@ -219,7 +234,7 @@ func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error { if err := elemdec(s, val.Index(i)); err == EOL { break } else if err != nil { - return err + return addErrorContext(err, fmt.Sprint("[", i, "]")) } } if i < val.Len() { @@ -248,7 +263,7 @@ func decodeListArray(s *Stream, val reflect.Value, elemdec decoder) error { if err := elemdec(s, val.Index(i)); err == EOL { break } else if err != nil { - return err + return addErrorContext(err, fmt.Sprint("[", i, "]")) } } if i < vlen { @@ -280,14 +295,14 @@ func decodeByteArray(s *Stream, val reflect.Value) error { switch kind { case Byte: if val.Len() == 0 { - return decodeError{"input string too long", val.Type()} + return &decodeError{msg: "input string too long", typ: val.Type()} } bv, _ := s.Uint() val.Index(0).SetUint(bv) zero(val, 1) case String: if uint64(val.Len()) < size { - return decodeError{"input string too long", val.Type()} + return &decodeError{msg: "input string too long", typ: val.Type()} } slice := val.Slice(0, int(size)).Interface().([]byte) if err := s.readFull(slice); err != nil { @@ -334,7 +349,7 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) { // too few elements. leave the rest at their zero value. break } else if err != nil { - return err + return addErrorContext(err, "."+typ.Field(f.index).Name) } } return wrapStreamError(s.ListEnd(), typ) @@ -599,7 +614,13 @@ func (s *Stream) Decode(val interface{}) error { if err != nil { return err } - return info.decoder(s, rval.Elem()) + + err = info.decoder(s, rval.Elem()) + if decErr, ok := err.(*decodeError); ok && len(decErr.ctx) > 0 { + // add decode target type to error so context has more meaning + decErr.ctx = append(decErr.ctx, fmt.Sprint("(", rtyp.Elem(), ")")) + } + return err } // Reset discards any information about the current decoding context diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 7a1743937..18ea63a09 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -231,7 +231,12 @@ var decodeTests = []decodeTest{ {input: "8D6162636465666768696A6B6C6D", ptr: new([]byte), value: []byte("abcdefghijklm")}, {input: "C0", ptr: new([]byte), value: []byte{}}, {input: "C3010203", ptr: new([]byte), value: []byte{1, 2, 3}}, - {input: "C3820102", ptr: new([]byte), error: "rlp: input string too long for uint8"}, + + { + input: "C3820102", + ptr: new([]byte), + error: "rlp: input string too long for uint8, decoding into ([]uint8)[0]", + }, // byte arrays {input: "01", ptr: new([5]byte), value: [5]byte{1}}, @@ -239,9 +244,22 @@ var decodeTests = []decodeTest{ {input: "850102030405", ptr: new([5]byte), value: [5]byte{1, 2, 3, 4, 5}}, {input: "C0", ptr: new([5]byte), value: [5]byte{}}, {input: "C3010203", ptr: new([5]byte), value: [5]byte{1, 2, 3, 0, 0}}, - {input: "C3820102", ptr: new([5]byte), error: "rlp: input string too long for uint8"}, - {input: "86010203040506", ptr: new([5]byte), error: "rlp: input string too long for [5]uint8"}, - {input: "850101", ptr: new([5]byte), error: io.ErrUnexpectedEOF.Error()}, + + { + input: "C3820102", + ptr: new([5]byte), + error: "rlp: input string too long for uint8, decoding into ([5]uint8)[0]", + }, + { + input: "86010203040506", + ptr: new([5]byte), + error: "rlp: input string too long for [5]uint8", + }, + { + input: "850101", + ptr: new([5]byte), + error: io.ErrUnexpectedEOF.Error(), + }, // byte array reuse (should be zeroed) {input: "850102030405", ptr: &sharedByteArray, value: [5]byte{1, 2, 3, 4, 5}}, @@ -272,13 +290,23 @@ var decodeTests = []decodeTest{ {input: "C0", ptr: new(simplestruct), value: simplestruct{0, ""}}, {input: "C105", ptr: new(simplestruct), value: simplestruct{5, ""}}, {input: "C50583343434", ptr: new(simplestruct), value: simplestruct{5, "444"}}, - {input: "C3010101", ptr: new(simplestruct), error: "rlp: input list has too many elements for rlp.simplestruct"}, { input: "C501C302C103", ptr: new(recstruct), value: recstruct{1, &recstruct{2, &recstruct{3, nil}}}, }, + { + input: "C3010101", + ptr: new(simplestruct), + error: "rlp: input list has too many elements for rlp.simplestruct", + }, + { + input: "C501C3C00000", + ptr: new(recstruct), + error: "rlp: expected input string or byte for uint, decoding into (rlp.recstruct).Child.I", + }, + // pointers {input: "00", ptr: new(*uint), value: (*uint)(nil)}, {input: "80", ptr: new(*uint), value: (*uint)(nil)}, -- cgit v1.2.3