diff --git a/binary/byteslice.go b/binary/byteslice.go index 1d0174b63..d1cd169a9 100644 --- a/binary/byteslice.go +++ b/binary/byteslice.go @@ -1,21 +1,35 @@ package binary import ( + . "github.com/tendermint/tendermint/common" "io" ) +const ( + ByteSliceChunk = 1024 +) + func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) { WriteUvarint(uint(len(bz)), w, n, err) WriteTo(bz, w, n, err) } func ReadByteSlice(r io.Reader, n *int64, err *error) []byte { - length := ReadUvarint(r, n, err) + length := int(ReadUvarint(r, n, err)) if *err != nil { return nil } - buf := make([]byte, int(length)) - ReadFull(buf, r, n, err) + + var buf, tmpBuf []byte + // read one ByteSliceChunk at a time and append + for i := 0; i*ByteSliceChunk < length; i++ { + tmpBuf = make([]byte, MinInt(ByteSliceChunk, length-i*ByteSliceChunk)) + ReadFull(tmpBuf, r, n, err) + if *err != nil { + return nil + } + buf = append(buf, tmpBuf...) + } return buf } diff --git a/binary/reflect.go b/binary/reflect.go index a517c4ab4..7ec4e2d24 100644 --- a/binary/reflect.go +++ b/binary/reflect.go @@ -12,6 +12,10 @@ import ( . "github.com/tendermint/tendermint/common" ) +const ( + ReflectSliceChunk = 1024 +) + type TypeInfo struct { Type reflect.Type // The type @@ -221,15 +225,25 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err * log.Debug("Read byteslice", "bytes", byteslice) rv.Set(reflect.ValueOf(byteslice)) } else { + var sliceRv reflect.Value // Read length length := int(ReadUvarint(r, n, err)) log.Debug(Fmt("Read length: %v", length)) - sliceRv := reflect.MakeSlice(rt, length, length) - // Read elems - for i := 0; i < length; i++ { - elemRv := sliceRv.Index(i) - readReflect(elemRv, elemRt, r, n, err) + sliceRv = reflect.MakeSlice(rt, 0, 0) + // read one ReflectSliceChunk at a time and append + for i := 0; i*ReflectSliceChunk < length; i++ { + l := MinInt(ReflectSliceChunk, length-i*ReflectSliceChunk) + tmpSliceRv := reflect.MakeSlice(rt, l, l) + for j := 0; j < l; j++ { + elemRv := tmpSliceRv.Index(j) + readReflect(elemRv, elemRt, r, n, err) + if *err != nil { + return + } + } + sliceRv = reflect.AppendSlice(sliceRv, tmpSliceRv) } + rv.Set(sliceRv) } diff --git a/binary/reflect_test.go b/binary/reflect_test.go index 9b854f513..3fd3f765a 100644 --- a/binary/reflect_test.go +++ b/binary/reflect_test.go @@ -6,6 +6,8 @@ import ( "reflect" "testing" "time" + + . "github.com/tendermint/tendermint/common" ) type SimpleStruct struct { @@ -447,3 +449,17 @@ func TestJSONFieldNames(t *testing.T) { } } } + +//------------------------------------------------------------------------------ + +func TestBadAlloc(t *testing.T) { + n, err := new(int64), new(error) + instance := new([]byte) + data := RandBytes(ByteSliceChunk * 100) + b := new(bytes.Buffer) + // this slice of data claims to be much bigger than it really is + WriteUvarint(uint(10000000000000000), b, n, err) + b.Write(data) + res := ReadBinary(instance, b, n, err) + fmt.Println(res, *err) +}