diff options
Diffstat (limited to 'src/pkg/encoding/gob')
-rw-r--r-- | src/pkg/encoding/gob/codec_test.go | 56 | ||||
-rw-r--r-- | src/pkg/encoding/gob/decode.go | 21 | ||||
-rw-r--r-- | src/pkg/encoding/gob/decoder.go | 8 | ||||
-rw-r--r-- | src/pkg/encoding/gob/encode.go | 2 | ||||
-rw-r--r-- | src/pkg/encoding/gob/encoder_test.go | 4 | ||||
-rw-r--r-- | src/pkg/encoding/gob/gobencdec_test.go | 19 |
6 files changed, 89 insertions, 21 deletions
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go index b40f78360..fa57f3761 100644 --- a/src/pkg/encoding/gob/codec_test.go +++ b/src/pkg/encoding/gob/codec_test.go @@ -1364,11 +1364,7 @@ type DT struct { S []string } -func TestDebugStruct(t *testing.T) { - if debugFunc == nil { - return - } - Register(OnTheFly{}) +func newDT() DT { var dt DT dt.A = 17 dt.B = "hello" @@ -1379,6 +1375,15 @@ func TestDebugStruct(t *testing.T) { dt.M = map[string]int{"one": 1, "two": 2} dt.T = [3]int{11, 22, 33} dt.S = []string{"hi", "joe"} + return dt +} + +func TestDebugStruct(t *testing.T) { + if debugFunc == nil { + return + } + Register(OnTheFly{}) + dt := newDT() b := new(bytes.Buffer) err := NewEncoder(b).Encode(dt) if err != nil { @@ -1458,3 +1463,44 @@ func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) { } } } + +// TestFuzzOneByte tries to decode corrupted input sequences +// and checks that no panic occurs. +func TestFuzzOneByte(t *testing.T) { + buf := new(bytes.Buffer) + Register(OnTheFly{}) + dt := newDT() + if err := NewEncoder(buf).Encode(dt); err != nil { + t.Fatal(err) + } + s := buf.String() + + indices := make([]int, 0, len(s)) + for i := 0; i < len(s); i++ { + switch i { + case 14, 167, 231, 265: // a slice length, corruptions are not handled yet. + continue + } + indices = append(indices, i) + } + if testing.Short() { + indices = []int{1, 111, 178} // known fixed panics + } + for _, i := range indices { + for j := 0; j < 256; j += 3 { + b := []byte(s) + b[i] ^= byte(j) + var e DT + func() { + defer func() { + if p := recover(); p != nil { + t.Errorf("crash for b[%d] ^= 0x%x", i, j) + panic(p) + } + }() + err := NewDecoder(bytes.NewReader(b)).Decode(&e) + _ = err + }() + } + } +} diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go index 3e76f4c90..d8513148e 100644 --- a/src/pkg/encoding/gob/decode.go +++ b/src/pkg/encoding/gob/decode.go @@ -654,21 +654,20 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { // decodeSlice decodes a slice and stores the slice header through p. // Slices are encoded as an unsigned length followed by the elements. -func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) { +func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) { nr := state.decodeUint() n := int(nr) if indir > 0 { - up := unsafe.Pointer(p) - if *(*unsafe.Pointer)(up) == nil { + if *(*unsafe.Pointer)(p) == nil { // Allocate the slice header. - *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer)) + *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]unsafe.Pointer)) } - p = *(*uintptr)(up) + p = *(*unsafe.Pointer)(p) } // Allocate storage for the slice elements, that is, the underlying array, // if the existing slice does not have the capacity. // Always write a header at p. - hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p)) + hdrp := (*reflect.SliceHeader)(p) if hdrp.Cap < n { hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer() hdrp.Cap = n @@ -686,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) { // but first it checks that the assignment will succeed. func setInterfaceValue(ivalue reflect.Value, value reflect.Value) { if !value.Type().AssignableTo(ivalue.Type()) { - errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type()) + errorf("%s is not assignable to type %s", value.Type(), ivalue.Type()) } ivalue.Set(value) } @@ -702,6 +701,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types errorf("invalid type name length %d", nr) } + if nr > uint64(state.b.Len()) { + errorf("invalid type name length %d: exceeds input size", nr) + } b := make([]byte, nr) state.b.Read(b) name := string(b) @@ -887,7 +889,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress) ovfl := overflow(name) op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { - state.dec.decodeSlice(t, state, uintptr(p), *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl) + state.dec.decodeSlice(t, state, p, *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl) } case reflect.Struct: @@ -1238,7 +1240,8 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { } engine := *enginePtr if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 { - if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 { + if engine.numInstr == 0 && st.NumField() > 0 && + dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 { name := base.Name() errorf("type mismatch: no fields matched compiling decoder for %s", name) } diff --git a/src/pkg/encoding/gob/decoder.go b/src/pkg/encoding/gob/decoder.go index 04f706ca5..3a769ec12 100644 --- a/src/pkg/encoding/gob/decoder.go +++ b/src/pkg/encoding/gob/decoder.go @@ -183,11 +183,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { return -1 } -// Decode reads the next value from the connection and stores +// Decode reads the next value from the input stream and stores // it in the data represented by the empty interface value. // If e is nil, the value will be discarded. Otherwise, // the value underlying e must be a pointer to the // correct type for the next data item received. +// If the input is at EOF, Decode returns io.EOF and +// does not modify e. func (dec *Decoder) Decode(e interface{}) error { if e == nil { return dec.DecodeValue(reflect.Value{}) @@ -202,10 +204,12 @@ func (dec *Decoder) Decode(e interface{}) error { return dec.DecodeValue(value) } -// DecodeValue reads the next value from the connection. +// DecodeValue reads the next value from the input stream. // If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value. // Otherwise, it stores the value into v. In that case, v must represent // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet()) +// If the input is at EOF, DecodeValue returns io.EOF and +// does not modify e. func (dec *Decoder) DecodeValue(v reflect.Value) error { if v.IsValid() { if v.Kind() == reflect.Ptr && !v.IsNil() { diff --git a/src/pkg/encoding/gob/encode.go b/src/pkg/encoding/gob/encode.go index d158b6442..7831c02d1 100644 --- a/src/pkg/encoding/gob/encode.go +++ b/src/pkg/encoding/gob/encode.go @@ -491,7 +491,7 @@ func isZero(val reflect.Value) bool { return !val.Bool() case reflect.Complex64, reflect.Complex128: return val.Complex() == 0 - case reflect.Chan, reflect.Func, reflect.Ptr: + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr: return val.IsNil() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return val.Int() == 0 diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go index 4ecf51d12..6445ce100 100644 --- a/src/pkg/encoding/gob/encoder_test.go +++ b/src/pkg/encoding/gob/encoder_test.go @@ -129,6 +129,8 @@ func TestBadData(t *testing.T) { corruptDataCheck("", io.EOF, t) corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t) corruptDataCheck("\x03now is the time for all good men", errBadType, t) + // issue 6323. + corruptDataCheck("\x04\x24foo", errRange, t) } // Types not supported at top level by the Encoder. @@ -630,7 +632,7 @@ func TestSliceReusesMemory(t *testing.T) { // Used to crash: negative count in recvMessage. func TestBadCount(t *testing.T) { b := []byte{0xfb, 0xa5, 0x82, 0x2f, 0xca, 0x1} - if err := NewDecoder(bytes.NewBuffer(b)).Decode(nil); err == nil { + if err := NewDecoder(bytes.NewReader(b)).Decode(nil); err == nil { t.Error("expected error from bad count") } else if err.Error() != errBadCount.Error() { t.Error("expected bad count error; got", err) diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go index 0193e2b67..157b7723a 100644 --- a/src/pkg/encoding/gob/gobencdec_test.go +++ b/src/pkg/encoding/gob/gobencdec_test.go @@ -705,13 +705,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) { } // Another bug: this caused a crash with the new Go1 Time type. -// We throw in a gob-encoding array, to test another case of isZero - +// We throw in a gob-encoding array, to test another case of isZero, +// and a struct containing an nil interface, to test a third. type isZeroBug struct { T time.Time S string I int A isZeroBugArray + F isZeroBugInterface } type isZeroBugArray [2]uint8 @@ -731,8 +732,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error { return nil } +type isZeroBugInterface struct { + I interface{} +} + +func (i isZeroBugInterface) GobEncode() (b []byte, e error) { + return []byte{}, nil +} + +func (i *isZeroBugInterface) GobDecode(data []byte) error { + return nil +} + func TestGobEncodeIsZero(t *testing.T) { - x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}} + x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}} b := new(bytes.Buffer) enc := NewEncoder(b) err := enc.Encode(x) |