mirror of
https://github.com/golang/go
synced 2024-11-25 06:57:58 -07:00
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
This commit is contained in:
parent
17bd39e7d9
commit
c94f5fb0ba
@ -951,32 +951,33 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
|
||||
// gobDecodeOpFor returns the op for a type that is known to implement
|
||||
// GobDecoder.
|
||||
func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
|
||||
rt := ut.user
|
||||
rcvrType := ut.user
|
||||
if ut.decIndir == -1 {
|
||||
rt = reflect.PtrTo(rt)
|
||||
rcvrType = reflect.PtrTo(rcvrType)
|
||||
} else if ut.decIndir > 0 {
|
||||
for i := int8(0); i < ut.decIndir; i++ {
|
||||
rt = rt.Elem()
|
||||
rcvrType = rcvrType.Elem()
|
||||
}
|
||||
}
|
||||
var op decOp
|
||||
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
|
||||
// Allocate the underlying data, but hold on to the address we have,
|
||||
// since we need it to get to the receiver's address.
|
||||
allocate(ut.base, uintptr(p), ut.indir)
|
||||
// Caller has gotten us to within one indirection of our value.
|
||||
if i.indir > 0 {
|
||||
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
|
||||
if ut.decIndir == -1 {
|
||||
// Need to climb up one level to turn value into pointer.
|
||||
v = reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
|
||||
v = reflect.NewValue(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
|
||||
} else {
|
||||
if ut.decIndir > 0 {
|
||||
p = decIndirect(p, int(ut.decIndir))
|
||||
v = reflect.NewValue(unsafe.Unreflect(rcvrType, p))
|
||||
}
|
||||
v = reflect.NewValue(unsafe.Unreflect(rt, p))
|
||||
state.dec.decodeGobDecoder(state, v, methodIndex(rcvrType, gobDecodeMethodName))
|
||||
}
|
||||
state.dec.decodeGobDecoder(state, v, methodIndex(rt, gobDecodeMethodName))
|
||||
}
|
||||
return &op, int(ut.decIndir)
|
||||
return &op, int(ut.indir)
|
||||
|
||||
}
|
||||
|
||||
@ -1197,10 +1198,6 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
|
||||
// Dereference down to the underlying struct type.
|
||||
ut := userType(val.Type())
|
||||
base := ut.base
|
||||
indir := ut.indir
|
||||
if ut.isGobDecoder {
|
||||
indir = int(ut.decIndir)
|
||||
}
|
||||
var enginePtr **decEngine
|
||||
enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
|
||||
if dec.err != nil {
|
||||
@ -1212,7 +1209,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
|
||||
name := base.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 {
|
||||
dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user