Skip to content

Commit 9c3fc83

Browse files
committed
encoding/gob: error rather than panic when decoding enormous slices
Fixes #8084. LGTM=ruiu R=golang-codereviews, ruiu CC=golang-codereviews https://golang.org/cl/142710043
1 parent dff461f commit 9c3fc83

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

src/encoding/gob/decode.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
312312
if n > state.b.Len() {
313313
errorf("%s data too long for buffer: %d", value.Type(), n)
314314
}
315+
if n > tooBig {
316+
errorf("byte slice too big: %d", n)
317+
}
315318
if value.Cap() < n {
316319
value.Set(reflect.MakeSlice(value.Type(), n, n))
317320
} else {
@@ -539,8 +542,15 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp
539542
// of interfaces, there will be buffer reloads.
540543
errorf("length of %s is negative (%d bytes)", value.Type(), u)
541544
}
545+
typ := value.Type()
546+
size := uint64(typ.Elem().Size())
547+
// Take care with overflow in this calculation.
548+
nBytes := u * size
549+
if nBytes > tooBig || (size > 0 && nBytes/size != u) {
550+
errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), n, size)
551+
}
542552
if value.Cap() < n {
543-
value.Set(reflect.MakeSlice(value.Type(), n, n))
553+
value.Set(reflect.MakeSlice(typ, n, n))
544554
} else {
545555
value.Set(value.Slice(0, n))
546556
}

src/encoding/gob/decoder.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import (
1313
"sync"
1414
)
1515

16+
// tooBig provides a sanity check for sizes; used in several places.
17+
// Upper limit of 1GB, allowing room to grow a little without overflow.
18+
// TODO: make this adjustable?
19+
const tooBig = 1 << 30
20+
1621
// A Decoder manages the receipt of type and data information read from the
1722
// remote side of a connection.
1823
type Decoder struct {
@@ -75,9 +80,7 @@ func (dec *Decoder) recvMessage() bool {
7580
dec.err = err
7681
return false
7782
}
78-
// Upper limit of 1GB, allowing room to grow a little without overflow.
79-
// TODO: We might want more control over this limit.
80-
if nbytes >= 1<<30 {
83+
if nbytes >= tooBig {
8184
dec.err = errBadCount
8285
return false
8386
}

src/encoding/gob/encoder_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -932,3 +932,25 @@ func Test29ElementSlice(t *testing.T) {
932932
return
933933
}
934934
}
935+
936+
// Don't crash, just give error when allocating a huge slice.
937+
// Issue 8084.
938+
func TestErrorForHugeSlice(t *testing.T) {
939+
// Encode an int slice.
940+
buf := new(bytes.Buffer)
941+
slice := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
942+
err := NewEncoder(buf).Encode(slice)
943+
if err != nil {
944+
t.Fatal("encode:", err)
945+
}
946+
// Reach into the buffer and smash the count to make the encoded slice very long.
947+
buf.Bytes()[buf.Len()-len(slice)-1] = 0xfa
948+
// Decode and see error.
949+
err = NewDecoder(buf).Decode(&slice)
950+
if err == nil {
951+
t.Fatal("decode: no error")
952+
}
953+
if !strings.Contains(err.Error(), "slice too big") {
954+
t.Fatal("decode: expected slice too big error, got %s", err.Error())
955+
}
956+
}

0 commit comments

Comments
 (0)