@@ -518,7 +518,7 @@ func decodeDecoder(s *Stream, val reflect.Value) error {
518518}
519519
520520// Kind represents the kind of value contained in an RLP stream.
521- type Kind int
521+ type Kind int8
522522
523523const (
524524 Byte Kind = iota
@@ -561,22 +561,16 @@ type ByteReader interface {
561561type Stream struct {
562562 r ByteReader
563563
564- // number of bytes remaining to be read from r.
565- remaining uint64
566- limited bool
567-
568- // auxiliary buffer for integer decoding
569- uintbuf []byte
570-
571- kind Kind // kind of value ahead
572- size uint64 // size of value ahead
573- byteval byte // value of single byte in type tag
574- kinderr error // error from last readKind
575- stack []listpos
564+ remaining uint64 // number of bytes remaining to be read from r
565+ size uint64 // size of value ahead
566+ kinderr error // error from last readKind
567+ stack []uint64 // list sizes
568+ uintbuf [8 ]byte // auxiliary buffer for integer decoding
569+ kind Kind // kind of value ahead
570+ byteval byte // value of single byte in type tag
571+ limited bool // true if input limit is in effect
576572}
577573
578- type listpos struct { pos , size uint64 }
579-
580574// NewStream creates a new decoding stream reading from r.
581575//
582576// If r implements the ByteReader interface, Stream will
@@ -646,8 +640,8 @@ func (s *Stream) Raw() ([]byte, error) {
646640 s .kind = - 1 // rearm Kind
647641 return []byte {s .byteval }, nil
648642 }
649- // the original header has already been read and is no longer
650- // available. read content and put a new header in front of it.
643+ // The original header has already been read and is no longer
644+ // available. Read content and put a new header in front of it.
651645 start := headsize (size )
652646 buf := make ([]byte , uint64 (start )+ size )
653647 if err := s .readFull (buf [start :]); err != nil {
@@ -730,7 +724,14 @@ func (s *Stream) List() (size uint64, err error) {
730724 if kind != List {
731725 return 0 , ErrExpectedList
732726 }
733- s .stack = append (s .stack , listpos {0 , size })
727+
728+ // Remove size of inner list from outer list before pushing the new size
729+ // onto the stack. This ensures that the remaining outer list size will
730+ // be correct after the matching call to ListEnd.
731+ if inList , limit := s .listLimit (); inList {
732+ s .stack [len (s .stack )- 1 ] = limit - size
733+ }
734+ s .stack = append (s .stack , size )
734735 s .kind = - 1
735736 s .size = 0
736737 return size , nil
@@ -739,17 +740,13 @@ func (s *Stream) List() (size uint64, err error) {
739740// ListEnd returns to the enclosing list.
740741// The input reader must be positioned at the end of a list.
741742func (s * Stream ) ListEnd () error {
742- if len (s .stack ) == 0 {
743+ // Ensure that no more data is remaining in the current list.
744+ if inList , listLimit := s .listLimit (); ! inList {
743745 return errNotInList
744- }
745- tos := s .stack [len (s .stack )- 1 ]
746- if tos .pos != tos .size {
746+ } else if listLimit > 0 {
747747 return errNotAtEOL
748748 }
749749 s .stack = s .stack [:len (s .stack )- 1 ] // pop
750- if len (s .stack ) > 0 {
751- s .stack [len (s .stack )- 1 ].pos += tos .size
752- }
753750 s .kind = - 1
754751 s .size = 0
755752 return nil
@@ -777,7 +774,7 @@ func (s *Stream) Decode(val interface{}) error {
777774
778775 err = decoder (s , rval .Elem ())
779776 if decErr , ok := err .(* decodeError ); ok && len (decErr .ctx ) > 0 {
780- // add decode target type to error so context has more meaning
777+ // Add decode target type to error so context has more meaning.
781778 decErr .ctx = append (decErr .ctx , fmt .Sprint ("(" , rtyp .Elem (), ")" ))
782779 }
783780 return err
@@ -800,6 +797,9 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) {
800797 case * bytes.Reader :
801798 s .remaining = uint64 (br .Len ())
802799 s .limited = true
800+ case * bytes.Buffer :
801+ s .remaining = uint64 (br .Len ())
802+ s .limited = true
803803 case * strings.Reader :
804804 s .remaining = uint64 (br .Len ())
805805 s .limited = true
@@ -818,10 +818,8 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) {
818818 s .size = 0
819819 s .kind = - 1
820820 s .kinderr = nil
821- if s .uintbuf == nil {
822- s .uintbuf = make ([]byte , 8 )
823- }
824821 s .byteval = 0
822+ s .uintbuf = [8 ]byte {}
825823}
826824
827825// Kind returns the kind and size of the next value in the
@@ -836,35 +834,29 @@ func (s *Stream) Reset(r io.Reader, inputLimit uint64) {
836834// the value. Subsequent calls to Kind (until the value is decoded)
837835// will not advance the input reader and return cached information.
838836func (s * Stream ) Kind () (kind Kind , size uint64 , err error ) {
839- var tos * listpos
840- if len (s .stack ) > 0 {
841- tos = & s .stack [len (s .stack )- 1 ]
842- }
843- if s .kind < 0 {
844- s .kinderr = nil
845- // Don't read further if we're at the end of the
846- // innermost list.
847- if tos != nil && tos .pos == tos .size {
848- return 0 , 0 , EOL
849- }
850- s .kind , s .size , s .kinderr = s .readKind ()
851- if s .kinderr == nil {
852- if tos == nil {
853- // At toplevel, check that the value is smaller
854- // than the remaining input length.
855- if s .limited && s .size > s .remaining {
856- s .kinderr = ErrValueTooLarge
857- }
858- } else {
859- // Inside a list, check that the value doesn't overflow the list.
860- if s .size > tos .size - tos .pos {
861- s .kinderr = ErrElemTooLarge
862- }
863- }
837+ if s .kind >= 0 {
838+ return s .kind , s .size , s .kinderr
839+ }
840+
841+ // Check for end of list. This needs to be done here because readKind
842+ // checks against the list size, and would return the wrong error.
843+ inList , listLimit := s .listLimit ()
844+ if inList && listLimit == 0 {
845+ return 0 , 0 , EOL
846+ }
847+ // Read the actual size tag.
848+ s .kind , s .size , s .kinderr = s .readKind ()
849+ if s .kinderr == nil {
850+ // Check the data size of the value ahead against input limits. This
851+ // is done here because many decoders require allocating an input
852+ // buffer matching the value size. Checking it here protects those
853+ // decoders from inputs declaring very large value size.
854+ if inList && s .size > listLimit {
855+ s .kinderr = ErrElemTooLarge
856+ } else if s .limited && s .size > s .remaining {
857+ s .kinderr = ErrValueTooLarge
864858 }
865859 }
866- // Note: this might return a sticky error generated
867- // by an earlier call to readKind.
868860 return s .kind , s .size , s .kinderr
869861}
870862
@@ -891,37 +883,35 @@ func (s *Stream) readKind() (kind Kind, size uint64, err error) {
891883 s .byteval = b
892884 return Byte , 0 , nil
893885 case b < 0xB8 :
894- // Otherwise, if a string is 0-55 bytes long,
895- // the RLP encoding consists of a single byte with value 0x80 plus the
896- // length of the string followed by the string. The range of the first
897- // byte is thus [0x80, 0xB7].
886+ // Otherwise, if a string is 0-55 bytes long, the RLP encoding consists
887+ // of a single byte with value 0x80 plus the length of the string
888+ // followed by the string. The range of the first byte is thus [0x80, 0xB7].
898889 return String , uint64 (b - 0x80 ), nil
899890 case b < 0xC0 :
900- // If a string is more than 55 bytes long, the
901- // RLP encoding consists of a single byte with value 0xB7 plus the length
902- // of the length of the string in binary form, followed by the length of
903- // the string, followed by the string. For example, a length-1024 string
904- // would be encoded as 0xB90400 followed by the string. The range of
905- // the first byte is thus [0xB8, 0xBF].
891+ // If a string is more than 55 bytes long, the RLP encoding consists of a
892+ // single byte with value 0xB7 plus the length of the length of the
893+ // string in binary form, followed by the length of the string, followed
894+ // by the string. For example, a length-1024 string would be encoded as
895+ // 0xB90400 followed by the string. The range of the first byte is thus
896+ // [0xB8, 0xBF].
906897 size , err = s .readUint (b - 0xB7 )
907898 if err == nil && size < 56 {
908899 err = ErrCanonSize
909900 }
910901 return String , size , err
911902 case b < 0xF8 :
912- // If the total payload of a list
913- // (i.e. the combined length of all its items) is 0-55 bytes long, the
914- // RLP encoding consists of a single byte with value 0xC0 plus the length
915- // of the list followed by the concatenation of the RLP encodings of the
916- // items. The range of the first byte is thus [0xC0, 0xF7].
903+ // If the total payload of a list (i.e. the combined length of all its
904+ // items) is 0-55 bytes long, the RLP encoding consists of a single byte
905+ // with value 0xC0 plus the length of the list followed by the
906+ // concatenation of the RLP encodings of the items. The range of the
907+ // first byte is thus [0xC0, 0xF7].
917908 return List , uint64 (b - 0xC0 ), nil
918909 default :
919- // If the total payload of a list is more than 55 bytes long,
920- // the RLP encoding consists of a single byte with value 0xF7
921- // plus the length of the length of the payload in binary
922- // form, followed by the length of the payload, followed by
923- // the concatenation of the RLP encodings of the items. The
924- // range of the first byte is thus [0xF8, 0xFF].
910+ // If the total payload of a list is more than 55 bytes long, the RLP
911+ // encoding consists of a single byte with value 0xF7 plus the length of
912+ // the length of the payload in binary form, followed by the length of
913+ // the payload, followed by the concatenation of the RLP encodings of
914+ // the items. The range of the first byte is thus [0xF8, 0xFF].
925915 size , err = s .readUint (b - 0xF7 )
926916 if err == nil && size < 56 {
927917 err = ErrCanonSize
@@ -940,22 +930,20 @@ func (s *Stream) readUint(size byte) (uint64, error) {
940930 return uint64 (b ), err
941931 default :
942932 start := int (8 - size )
943- for i := 0 ; i < start ; i ++ {
944- s .uintbuf [i ] = 0
945- }
933+ s .uintbuf = [8 ]byte {}
946934 if err := s .readFull (s .uintbuf [start :]); err != nil {
947935 return 0 , err
948936 }
949937 if s .uintbuf [start ] == 0 {
950- // Note: readUint is also used to decode integer
951- // values. The error needs to be adjusted to become
952- // ErrCanonInt in this case.
938+ // Note: readUint is also used to decode integer values.
939+ // The error needs to be adjusted to become ErrCanonInt in this case.
953940 return 0 , ErrCanonSize
954941 }
955- return binary .BigEndian .Uint64 (s .uintbuf ), nil
942+ return binary .BigEndian .Uint64 (s .uintbuf [:] ), nil
956943 }
957944}
958945
946+ // readFull reads into buf from the underlying stream.
959947func (s * Stream ) readFull (buf []byte ) (err error ) {
960948 if err := s .willRead (uint64 (len (buf ))); err != nil {
961949 return err
@@ -977,6 +965,7 @@ func (s *Stream) readFull(buf []byte) (err error) {
977965 return err
978966}
979967
968+ // readByte reads a single byte from the underlying stream.
980969func (s * Stream ) readByte () (byte , error ) {
981970 if err := s .willRead (1 ); err != nil {
982971 return 0 , err
@@ -988,16 +977,16 @@ func (s *Stream) readByte() (byte, error) {
988977 return b , err
989978}
990979
980+ // willRead is called before any read from the underlying stream. It checks
981+ // n against size limits, and updates the limits if n doesn't overflow them.
991982func (s * Stream ) willRead (n uint64 ) error {
992983 s .kind = - 1 // rearm Kind
993984
994- if len (s .stack ) > 0 {
995- // check list overflow
996- tos := s .stack [len (s .stack )- 1 ]
997- if n > tos .size - tos .pos {
985+ if inList , limit := s .listLimit (); inList {
986+ if n > limit {
998987 return ErrElemTooLarge
999988 }
1000- s .stack [len (s .stack )- 1 ]. pos += n
989+ s .stack [len (s .stack )- 1 ] = limit - n
1001990 }
1002991 if s .limited {
1003992 if n > s .remaining {
@@ -1007,3 +996,11 @@ func (s *Stream) willRead(n uint64) error {
1007996 }
1008997 return nil
1009998}
999+
1000+ // listLimit returns the amount of data remaining in the innermost list.
1001+ func (s * Stream ) listLimit () (inList bool , limit uint64 ) {
1002+ if len (s .stack ) == 0 {
1003+ return false , 0
1004+ }
1005+ return true , s .stack [len (s .stack )- 1 ]
1006+ }
0 commit comments