From 8e6cf5f70c77daadf1b2c798f227031be156a904 Mon Sep 17 00:00:00 2001 From: =?utf8?q?H=C3=A5vard=20Haugen?= Date: Wed, 28 Jan 2015 23:07:05 +0100 Subject: [PATCH] encoding/gob: clean up decoderMap after errBadType When decoding an invalid typeId the associated *decEngine was not removed from decoderMap. If the decoder was run again on the same input a nil *decEngine was found in the map and assumed to be initialized, resulting in a panic. Fixes #9649 Change-Id: I5bb51808362a21c09228c2705a658f073e5b59b3 Reviewed-on: https://go-review.googlesource.com/3509 Reviewed-by: Rob Pike --- src/encoding/gob/codec_test.go | 19 +++++++++++++++++++ src/encoding/gob/decode.go | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go index 56a7298fa5..c2583bfee3 100644 --- a/src/encoding/gob/codec_test.go +++ b/src/encoding/gob/codec_test.go @@ -1473,3 +1473,22 @@ func TestFuzzOneByte(t *testing.T) { } } } + +// Don't crash, just give error with invalid type id. +// Issue 9649. +func TestErrorInvalidTypeId(t *testing.T) { + data := []byte{0x01, 0x00, 0x01, 0x00} + d := NewDecoder(bytes.NewReader(data)) + // When running d.Decode(&foo) the first time the decoder stops + // after []byte{0x01, 0x00} and reports an errBadType. Running + // d.Decode(&foo) again on exactly the same input sequence should + // give another errBadType, but instead caused a panic because + // decoderMap wasn't cleaned up properly after the first error. + for i := 0; i < 2; i++ { + var foo struct{} + err := d.Decode(&foo) + if err != errBadType { + t.Fatal("decode: expected %s, got %s", errBadType, err) + } + } +} diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index f1c597086d..3f34cbac57 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -1051,6 +1051,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err // compileDec compiles the decoder engine for a value. If the value is not a struct, // it calls out to compileSingle. func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) { + defer catchError(&err) rt := ut.base srt := rt if srt.Kind() != reflect.Struct || ut.externalDec != 0 { @@ -1163,8 +1164,9 @@ func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) { value = decAlloc(value) engine := *enginePtr if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 { + wt := dec.wireType[wireId] if engine.numInstr == 0 && st.NumField() > 0 && - dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 { + wt != nil && len(wt.StructT.Field) > 0 { name := base.Name() errorf("type mismatch: no fields matched compiling decoder for %s", name) } -- 2.48.1