mirror of
https://github.com/golang/go
synced 2024-11-21 23:24:41 -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:
parent
c55d0c4dd7
commit
9ddc2b5688
@ -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
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user