Commit c94f5fb0 authored by Rob Pike's avatar Rob Pike

gob: fix handling of indirect receivers for GobDecoders.

The previous code was just wrong. Let's not talk about it.
Passes iant's new test.

R=rsc, iant, iant2
CC=golang-dev
https://golang.org/cl/4396053
parent 17bd39e7
...@@ -951,32 +951,33 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { ...@@ -951,32 +951,33 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
// gobDecodeOpFor returns the op for a type that is known to implement // gobDecodeOpFor returns the op for a type that is known to implement
// GobDecoder. // GobDecoder.
func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) { func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
rt := ut.user rcvrType := ut.user
if ut.decIndir == -1 { if ut.decIndir == -1 {
rt = reflect.PtrTo(rt) rcvrType = reflect.PtrTo(rcvrType)
} else if ut.decIndir > 0 { } else if ut.decIndir > 0 {
for i := int8(0); i < ut.decIndir; i++ { for i := int8(0); i < ut.decIndir; i++ {
rt = rt.Elem() rcvrType = rcvrType.Elem()
} }
} }
var op decOp var op decOp
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
// Allocate the underlying data, but hold on to the address we have, // Caller has gotten us to within one indirection of our value.
// since we need it to get to the receiver's address. if i.indir > 0 {
allocate(ut.base, uintptr(p), ut.indir) if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.New(ut.base)
}
}
// Now p is a pointer to the base type. Do we need to climb out to
// get to the receiver type?
var v reflect.Value var v reflect.Value
if ut.decIndir == -1 { if ut.decIndir == -1 {
// Need to climb up one level to turn value into pointer. v = reflect.NewValue(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
v = reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
} else { } else {
if ut.decIndir > 0 { v = reflect.NewValue(unsafe.Unreflect(rcvrType, p))
p = decIndirect(p, int(ut.decIndir))
}
v = reflect.NewValue(unsafe.Unreflect(rt, p))
} }
state.dec.decodeGobDecoder(state, v, methodIndex(rt, gobDecodeMethodName)) state.dec.decodeGobDecoder(state, v, methodIndex(rcvrType, gobDecodeMethodName))
} }
return &op, int(ut.decIndir) return &op, int(ut.indir)
} }
...@@ -1197,10 +1198,6 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { ...@@ -1197,10 +1198,6 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
// Dereference down to the underlying struct type. // Dereference down to the underlying struct type.
ut := userType(val.Type()) ut := userType(val.Type())
base := ut.base base := ut.base
indir := ut.indir
if ut.isGobDecoder {
indir = int(ut.decIndir)
}
var enginePtr **decEngine var enginePtr **decEngine
enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut) enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
if dec.err != nil { if dec.err != nil {
...@@ -1212,7 +1209,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { ...@@ -1212,7 +1209,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
name := base.Name() name := base.Name()
errorf("gob: type mismatch: no fields matched compiling decoder for %s", name) errorf("gob: type mismatch: no fields matched compiling decoder for %s", name)
} }
dec.decodeStruct(engine, ut, uintptr(val.UnsafeAddr()), indir) dec.decodeStruct(engine, ut, uintptr(val.UnsafeAddr()), ut.indir)
} else { } else {
dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr())) dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr()))
} }
......
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