1
0
mirror of https://github.com/golang/go synced 2024-11-22 04:34:39 -07:00

gob: fix allocation for singletons.

Code was double-allocating in some cases.
Fixes #2267.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5093042
This commit is contained in:
Rob Pike 2011-09-20 11:28:00 -07:00
parent c55d0c4dd7
commit 9ddc2b5688
2 changed files with 44 additions and 13 deletions

View File

@ -467,20 +467,17 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
// decodeSingle decodes a top-level value that is not a struct and stores it through p. // decodeSingle decodes a top-level value that is not a struct and stores it through p.
// Such values are preceded by a zero, making them have the memory layout of a // Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number). // struct field (although with an illegal field number).
func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) (err os.Error) { func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) (err os.Error) {
indir := ut.indir
if ut.isGobDecoder {
indir = int(ut.decIndir)
}
p = allocate(ut.base, p, indir)
state := dec.newDecoderState(&dec.buf) state := dec.newDecoderState(&dec.buf)
state.fieldnum = singletonField state.fieldnum = singletonField
basep := p
delta := int(state.decodeUint()) delta := int(state.decodeUint())
if delta != 0 { if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton") errorf("decode: corrupted data: non-zero delta for singleton")
} }
instr := &engine.instr[singletonField] instr := &engine.instr[singletonField]
if instr.indir != ut.indir {
return os.NewError("gob: internal error: inconsistent indirection")
}
ptr := unsafe.Pointer(basep) // offset will be zero ptr := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 1 { if instr.indir > 1 {
ptr = decIndirect(ptr, instr.indir) ptr = decIndirect(ptr, instr.indir)
@ -1069,10 +1066,7 @@ func (dec *Decoder) typeString(remoteId typeId) string {
// compileSingle compiles the decoder engine for a non-struct top-level value, including // compileSingle compiles the decoder engine for a non-struct top-level value, including
// GobDecoders. // GobDecoders.
func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) { func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
rt := ut.base rt := ut.user
if ut.isGobDecoder {
rt = ut.user
}
engine = new(decEngine) engine = new(decEngine)
engine.instr = make([]decInstr, 1) // one item engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do name := rt.String() // best we can do
@ -1202,7 +1196,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
dec.decodeIgnoredValue(wireId) dec.decodeIgnoredValue(wireId)
return return
} }
// Dereference down to the underlying struct type. // Dereference down to the underlying type.
ut := userType(val.Type()) ut := userType(val.Type())
base := ut.base base := ut.base
var enginePtr **decEngine var enginePtr **decEngine

View File

@ -424,7 +424,7 @@ func TestGobEncoderNonStructSingleton(t *testing.T) {
t.Fatal("decode error:", err) t.Fatal("decode error:", err)
} }
if x != 1234 { if x != 1234 {
t.Errorf("expected 1234 got %c", x) t.Errorf("expected 1234 got %d", x)
} }
} }
@ -488,3 +488,40 @@ func TestGobEncoderIgnoreNilEncoder(t *testing.T) {
t.Errorf("expected x.G = nil, got %v", x.G) t.Errorf("expected x.G = nil, got %v", x.G)
} }
} }
type gobDecoderBug0 struct {
foo, bar string
}
func (br *gobDecoderBug0) String() string {
return br.foo + "-" + br.bar
}
func (br *gobDecoderBug0) GobEncode() ([]byte, os.Error) {
return []byte(br.String()), nil
}
func (br *gobDecoderBug0) GobDecode(b []byte) os.Error {
br.foo = "foo"
br.bar = "bar"
return nil
}
// This was a bug: the receiver has a different indirection level
// than the variable.
func TestGobEncoderExtraIndirect(t *testing.T) {
gdb := &gobDecoderBug0{"foo", "bar"}
buf := new(bytes.Buffer)
e := NewEncoder(buf)
if err := e.Encode(gdb); err != nil {
t.Fatalf("encode: %v", err)
}
d := NewDecoder(buf)
var got *gobDecoderBug0
if err := d.Decode(&got); err != nil {
t.Fatalf("decode: %v", err)
}
if got.foo != gdb.foo || got.bar != gdb.bar {
t.Errorf("got = %q, want %q", got, gdb)
}
}