Browse Source

binary: prevent runaway alloc

pull/61/head
Ethan Buchman 10 years ago
parent
commit
b3b6bfb312
3 changed files with 52 additions and 8 deletions
  1. +17
    -3
      binary/byteslice.go
  2. +19
    -5
      binary/reflect.go
  3. +16
    -0
      binary/reflect_test.go

+ 17
- 3
binary/byteslice.go View File

@ -1,21 +1,35 @@
package binary package binary
import ( import (
. "github.com/tendermint/tendermint/common"
"io" "io"
) )
const (
ByteSliceChunk = 1024
)
func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) { func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) {
WriteUvarint(uint(len(bz)), w, n, err) WriteUvarint(uint(len(bz)), w, n, err)
WriteTo(bz, w, n, err) WriteTo(bz, w, n, err)
} }
func ReadByteSlice(r io.Reader, n *int64, err *error) []byte { func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
length := ReadUvarint(r, n, err)
length := int(ReadUvarint(r, n, err))
if *err != nil { if *err != nil {
return 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 return buf
} }


+ 19
- 5
binary/reflect.go View File

@ -12,6 +12,10 @@ import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
) )
const (
ReflectSliceChunk = 1024
)
type TypeInfo struct { type TypeInfo struct {
Type reflect.Type // The type 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) log.Debug("Read byteslice", "bytes", byteslice)
rv.Set(reflect.ValueOf(byteslice)) rv.Set(reflect.ValueOf(byteslice))
} else { } else {
var sliceRv reflect.Value
// Read length // Read length
length := int(ReadUvarint(r, n, err)) length := int(ReadUvarint(r, n, err))
log.Debug(Fmt("Read length: %v", length)) 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) rv.Set(sliceRv)
} }


+ 16
- 0
binary/reflect_test.go View File

@ -6,6 +6,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"time" "time"
. "github.com/tendermint/tendermint/common"
) )
type SimpleStruct struct { 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)
}

Loading…
Cancel
Save