// 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
// struct field (although with an illegal field number).
-func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) (err os.Error) {
- indir := ut.indir
- if ut.isGobDecoder {
- indir = int(ut.decIndir)
- }
- p = allocate(ut.base, p, indir)
+func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) (err os.Error) {
state := dec.newDecoderState(&dec.buf)
state.fieldnum = singletonField
- basep := p
delta := int(state.decodeUint())
if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton")
}
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
if instr.indir > 1 {
ptr = decIndirect(ptr, instr.indir)
// compileSingle compiles the decoder engine for a non-struct top-level value, including
// GobDecoders.
func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
- rt := ut.base
- if ut.isGobDecoder {
- rt = ut.user
- }
+ rt := ut.user
engine = new(decEngine)
engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do
dec.decodeIgnoredValue(wireId)
return
}
- // Dereference down to the underlying struct type.
+ // Dereference down to the underlying type.
ut := userType(val.Type())
base := ut.base
var enginePtr **decEngine
t.Fatal("decode error:", err)
}
if x != 1234 {
- t.Errorf("expected 1234 got %c", x)
+ t.Errorf("expected 1234 got %d", x)
}
}
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)
+ }
+}