diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index 2367650c8ba6e52c378091db5536baa04830f36c..502209a8a8085b78e60dd2fb721d83f37123bc6a 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -312,6 +312,9 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) { if n > state.b.Len() { errorf("%s data too long for buffer: %d", value.Type(), n) } + if n > tooBig { + errorf("byte slice too big: %d", n) + } if value.Cap() < n { value.Set(reflect.MakeSlice(value.Type(), n, n)) } else { @@ -539,8 +542,15 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp // of interfaces, there will be buffer reloads. errorf("length of %s is negative (%d bytes)", value.Type(), u) } + typ := value.Type() + size := uint64(typ.Elem().Size()) + // Take care with overflow in this calculation. + nBytes := u * size + if nBytes > tooBig || (size > 0 && nBytes/size != u) { + errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), n, size) + } if value.Cap() < n { - value.Set(reflect.MakeSlice(value.Type(), n, n)) + value.Set(reflect.MakeSlice(typ, n, n)) } else { value.Set(value.Slice(0, n)) } diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index 3a769ec1254ad15d080f6a61c8741eb343835352..dcad7a0e480d07bb42b98caed2d3259aeb24e6e8 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -13,6 +13,11 @@ import ( "sync" ) +// tooBig provides a sanity check for sizes; used in several places. +// Upper limit of 1GB, allowing room to grow a little without overflow. +// TODO: make this adjustable? +const tooBig = 1 << 30 + // A Decoder manages the receipt of type and data information read from the // remote side of a connection. type Decoder struct { @@ -75,9 +80,7 @@ func (dec *Decoder) recvMessage() bool { dec.err = err return false } - // Upper limit of 1GB, allowing room to grow a little without overflow. - // TODO: We might want more control over this limit. - if nbytes >= 1<<30 { + if nbytes >= tooBig { dec.err = errBadCount return false } diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index 376df82f15e424e8ee67a67f76185f12cee289e3..0ea4c0ec8e5f479c5eff8d973353d03ea08d30ae 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -932,3 +932,25 @@ func Test29ElementSlice(t *testing.T) { return } } + +// Don't crash, just give error when allocating a huge slice. +// Issue 8084. +func TestErrorForHugeSlice(t *testing.T) { + // Encode an int slice. + buf := new(bytes.Buffer) + slice := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + err := NewEncoder(buf).Encode(slice) + if err != nil { + t.Fatal("encode:", err) + } + // Reach into the buffer and smash the count to make the encoded slice very long. + buf.Bytes()[buf.Len()-len(slice)-1] = 0xfa + // Decode and see error. + err = NewDecoder(buf).Decode(&slice) + if err == nil { + t.Fatal("decode: no error") + } + if !strings.Contains(err.Error(), "slice too big") { + t.Fatal("decode: expected slice too big error, got %s", err.Error()) + } +}