Commit 420f713b authored by Rob Pike's avatar Rob Pike

encoding/gob: cache engine for user type, not base type

When we build the encode engine for a recursive type, we
mustn't disregard the indirections or we can try to reuse an
engine at the wrong indirection level.

Fixes #3026.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5675087
parent 7737e19b
...@@ -473,7 +473,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint ...@@ -473,7 +473,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint
} }
instr := &engine.instr[singletonField] instr := &engine.instr[singletonField]
if instr.indir != ut.indir { if instr.indir != ut.indir {
errorf("gob: internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir) errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
} }
ptr := unsafe.Pointer(basep) // offset will be zero ptr := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 1 { if instr.indir > 1 {
...@@ -1149,7 +1149,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn ...@@ -1149,7 +1149,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
// getDecEnginePtr returns the engine for the specified type. // getDecEnginePtr returns the engine for the specified type.
func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) { func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) {
rt := ut.base rt := ut.user
decoderMap, ok := dec.decoderCache[rt] decoderMap, ok := dec.decoderCache[rt]
if !ok { if !ok {
decoderMap = make(map[typeId]**decEngine) decoderMap = make(map[typeId]**decEngine)
......
...@@ -712,3 +712,27 @@ func TestGobPtrSlices(t *testing.T) { ...@@ -712,3 +712,27 @@ func TestGobPtrSlices(t *testing.T) {
t.Fatal("got %v; wanted %v", out, in) t.Fatal("got %v; wanted %v", out, in)
} }
} }
// getDecEnginePtr cached engine for ut.base instead of ut.user so we passed
// a *map and then tried to reuse its engine to decode the inner map.
func TestPtrToMapOfMap(t *testing.T) {
Register(make(map[string]interface{}))
subdata := make(map[string]interface{})
subdata["bar"] = "baz"
data := make(map[string]interface{})
data["foo"] = subdata
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(data)
if err != nil {
t.Fatal("encode:", err)
}
var newData map[string]interface{}
err = NewDecoder(b).Decode(&newData)
if err != nil {
t.Fatal("decode:", err)
}
if !reflect.DeepEqual(data, newData) {
t.Fatalf("expected %v got %v", data, newData)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment