summaryrefslogtreecommitdiff
path: root/src/pkg/gob
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/gob')
-rw-r--r--src/pkg/gob/codec_test.go3
-rw-r--r--src/pkg/gob/debug.go2
-rw-r--r--src/pkg/gob/decode.go126
-rw-r--r--src/pkg/gob/decoder.go24
-rw-r--r--src/pkg/gob/doc.go2
-rw-r--r--src/pkg/gob/encode.go26
-rw-r--r--src/pkg/gob/encoder.go7
-rw-r--r--src/pkg/gob/encoder_test.go39
-rw-r--r--src/pkg/gob/error.go3
-rw-r--r--src/pkg/gob/gobencdec_test.go84
-rw-r--r--src/pkg/gob/type.go60
-rw-r--r--src/pkg/gob/type_test.go28
12 files changed, 265 insertions, 139 deletions
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
index 28042ccaa..8961336cd 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/gob/codec_test.go
@@ -999,13 +999,12 @@ type Bad0 struct {
C float64
}
-
func TestInvalidField(t *testing.T) {
var bad0 Bad0
bad0.CH = make(chan int)
b := new(bytes.Buffer)
dummyEncoder := new(Encoder) // sufficient for this purpose.
- dummyEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
+ dummyEncoder.encode(b, reflect.ValueOf(&bad0), userType(reflect.TypeOf(&bad0)))
if err := dummyEncoder.err; err == nil {
t.Error("expected error; got none")
} else if strings.Index(err.String(), "type") < 0 {
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
index 69c83bda7..79aee7788 100644
--- a/src/pkg/gob/debug.go
+++ b/src/pkg/gob/debug.go
@@ -335,7 +335,7 @@ func (deb *debugger) string() string {
func (deb *debugger) delta(expect int) int {
delta := int(deb.uint64())
if delta < 0 || (expect >= 0 && delta != expect) {
- errorf("gob decode: corrupted type: delta %d expected %d", delta, expect)
+ errorf("decode: corrupted type: delta %d expected %d", delta, expect)
}
return delta
}
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index 51fac798d..0e86df6b5 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -406,7 +406,7 @@ func decUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) {
func decString(i *decInstr, state *decoderState, p unsafe.Pointer) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]byte))
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(string))
}
p = *(*unsafe.Pointer)(p)
}
@@ -468,7 +468,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr)
basep := p
delta := int(state.decodeUint())
if delta != 0 {
- errorf("gob decode: corrupted data: non-zero delta for singleton")
+ errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
ptr := unsafe.Pointer(basep) // offset will be zero
@@ -493,7 +493,7 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr,
for state.b.Len() > 0 {
delta := int(state.decodeUint())
if delta < 0 {
- errorf("gob decode: corrupted data: negative delta")
+ errorf("decode: corrupted data: negative delta")
}
if delta == 0 { // struct terminator is zero delta fieldnum
break
@@ -521,7 +521,7 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) {
for state.b.Len() > 0 {
delta := int(state.decodeUint())
if delta < 0 {
- errorf("gob ignore decode: corrupted data: negative delta")
+ errorf("ignore decode: corrupted data: negative delta")
}
if delta == 0 { // struct terminator is zero delta fieldnum
break
@@ -544,7 +544,7 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) {
state.fieldnum = singletonField
delta := int(state.decodeUint())
if delta != 0 {
- errorf("gob decode: corrupted data: non-zero delta for singleton")
+ errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
instr.op(instr, state, unsafe.Pointer(nil))
@@ -572,7 +572,7 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintpt
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
if n := state.decodeUint(); n != uint64(length) {
- errorf("gob: length mismatch in decodeArray")
+ errorf("length mismatch in decodeArray")
}
dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
}
@@ -581,7 +581,7 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintpt
// unlike the other items we can't use a pointer directly.
func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
instr := &decInstr{op, 0, indir, 0, ovfl}
- up := unsafe.Pointer(v.UnsafeAddr())
+ up := unsafe.Pointer(unsafeAddr(v))
if indir > 1 {
up = decIndirect(up, indir)
}
@@ -605,11 +605,11 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr,
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
- v := reflect.NewValue(unsafe.Unreflect(mtyp, unsafe.Pointer(p)))
+ v := reflect.ValueOf(unsafe.Unreflect(mtyp, unsafe.Pointer(p)))
n := int(state.decodeUint())
for i := 0; i < n; i++ {
- key := decodeIntoValue(state, keyOp, keyIndir, reflect.Zero(mtyp.Key()), ovfl)
- elem := decodeIntoValue(state, elemOp, elemIndir, reflect.Zero(mtyp.Elem()), ovfl)
+ key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
+ elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl)
v.SetMapIndex(key, elem)
}
}
@@ -625,7 +625,7 @@ func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length
// ignoreArray discards the data for an array value with no destination.
func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
if n := state.decodeUint(); n != uint64(length) {
- errorf("gob: length mismatch in ignoreArray")
+ errorf("length mismatch in ignoreArray")
}
dec.ignoreArrayHelper(state, elemOp, length)
}
@@ -667,18 +667,12 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
}
-// setInterfaceValue sets an interface value to a concrete value through
-// reflection. If the concrete value does not implement the interface, the
-// setting will panic. This routine turns the panic into an error return.
-// This dance avoids manually checking that the value satisfies the
-// interface.
-// TODO(rsc): avoid panic+recover after fixing issue 327.
+// setInterfaceValue sets an interface value to a concrete value,
+// but first it checks that the assignment will succeed.
func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
- defer func() {
- if e := recover(); e != nil {
- error(e.(os.Error))
- }
- }()
+ if !value.Type().AssignableTo(ivalue.Type()) {
+ errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+ }
ivalue.Set(value)
}
@@ -686,8 +680,8 @@ func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
// Interfaces are encoded as the name of a concrete type followed by a value.
// If the name is empty, the value is nil and no value is sent.
func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p uintptr, indir int) {
- // Create an interface reflect.Value. We need one even for the nil case.
- ivalue := reflect.Zero(ityp)
+ // Create a writable interface reflect.Value. We need one even for the nil case.
+ ivalue := allocValue(ityp)
// Read the name of the concrete type.
b := make([]byte, state.decodeUint())
state.b.Read(b)
@@ -701,7 +695,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
// The concrete type must be registered.
typ, ok := nameToConcreteType[name]
if !ok {
- errorf("gob: name not registered for interface: %q", name)
+ errorf("name not registered for interface: %q", name)
}
// Read the type id of the concrete value.
concreteId := dec.decodeTypeSequence(true)
@@ -712,7 +706,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
// in case we want to ignore the value by skipping it completely).
state.decodeUint()
// Read the concrete value.
- value := reflect.Zero(typ)
+ value := allocValue(typ)
dec.decodeValue(concreteId, value)
if dec.err != nil {
error(dec.err)
@@ -880,7 +874,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
}
}
if op == nil {
- errorf("gob: decode can't handle type %s", rt.String())
+ errorf("decode can't handle type %s", rt.String())
}
return &op, indir
}
@@ -901,7 +895,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
wire := dec.wireType[wireId]
switch {
case wire == nil:
- errorf("gob: bad data: undefined type %s", wireId.string())
+ errorf("bad data: undefined type %s", wireId.string())
case wire.ArrayT != nil:
elemId := wire.ArrayT.Elem
elemOp := dec.decIgnoreOpFor(elemId)
@@ -943,7 +937,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
}
}
if op == nil {
- errorf("gob: bad data: ignore can't handle type %s", wireId.string())
+ errorf("bad data: ignore can't handle type %s", wireId.string())
}
return op
}
@@ -951,32 +945,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.ValueOf(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
} else {
- if ut.decIndir > 0 {
- p = decIndirect(p, int(ut.decIndir))
- }
- v = reflect.NewValue(unsafe.Unreflect(rt, p))
+ v = reflect.ValueOf(unsafe.Unreflect(rcvrType, 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)
}
@@ -1111,7 +1106,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
wireStruct = wire.StructT
}
if wireStruct == nil {
- errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String())
+ errorf("type mismatch in decoder: want struct type %s; got non-struct", rt.String())
}
engine = new(decEngine)
engine.instr = make([]decInstr, len(wireStruct.Field))
@@ -1120,7 +1115,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ {
wireField := wireStruct.Field[fieldnum]
if wireField.Name == "" {
- errorf("gob: empty name for remote field of type %s", wireStruct.Name)
+ errorf("empty name for remote field of type %s", wireStruct.Name)
}
ovfl := overflow(wireField.Name)
// Find the field of the local type with the same name.
@@ -1132,7 +1127,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
continue
}
if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
- errorf("gob: wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
+ errorf("wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
}
op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
engine.instr[fieldnum] = decInstr{*op, fieldnum, indir, uintptr(localField.Offset), ovfl}
@@ -1164,7 +1159,7 @@ func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePt
// emptyStruct is the type we compile into when ignoring a struct value.
type emptyStruct struct{}
-var emptyStructType = reflect.Typeof(emptyStruct{})
+var emptyStructType = reflect.TypeOf(emptyStruct{})
// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
@@ -1197,10 +1192,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 {
@@ -1210,11 +1201,11 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
if st := base; st.Kind() == reflect.Struct && !ut.isGobDecoder {
if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
name := base.Name()
- errorf("gob: type mismatch: no fields matched compiling decoder for %s", name)
+ errorf("type mismatch: no fields matched compiling decoder for %s", name)
}
- dec.decodeStruct(engine, ut, uintptr(val.UnsafeAddr()), indir)
+ dec.decodeStruct(engine, ut, uintptr(unsafeAddr(val)), ut.indir)
} else {
- dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr()))
+ dec.decodeSingle(engine, ut, uintptr(unsafeAddr(val)))
}
}
@@ -1235,7 +1226,7 @@ func (dec *Decoder) decodeIgnoredValue(wireId typeId) {
func init() {
var iop, uop decOp
- switch reflect.Typeof(int(0)).Bits() {
+ switch reflect.TypeOf(int(0)).Bits() {
case 32:
iop = decInt32
uop = decUint32
@@ -1249,7 +1240,7 @@ func init() {
decOpTable[reflect.Uint] = uop
// Finally uintptr
- switch reflect.Typeof(uintptr(0)).Bits() {
+ switch reflect.TypeOf(uintptr(0)).Bits() {
case 32:
uop = decUint32
case 64:
@@ -1259,3 +1250,26 @@ func init() {
}
decOpTable[reflect.Uintptr] = uop
}
+
+// Gob assumes it can call UnsafeAddr on any Value
+// in order to get a pointer it can copy data from.
+// Values that have just been created and do not point
+// into existing structs or slices cannot be addressed,
+// so simulate it by returning a pointer to a copy.
+// Each call allocates once.
+func unsafeAddr(v reflect.Value) uintptr {
+ if v.CanAddr() {
+ return v.UnsafeAddr()
+ }
+ x := reflect.New(v.Type()).Elem()
+ x.Set(v)
+ return x.UnsafeAddr()
+}
+
+// Gob depends on being able to take the address
+// of zeroed Values it creates, so use this wrapper instead
+// of the standard reflect.Zero.
+// Each call allocates once.
+func allocValue(t reflect.Type) reflect.Value {
+ return reflect.New(t).Elem()
+}
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
index a631c27a2..ea2f62ec5 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/gob/decoder.go
@@ -50,7 +50,7 @@ func (dec *Decoder) recvType(id typeId) {
// Type:
wire := new(wireType)
- dec.decodeValue(tWireType, reflect.NewValue(wire))
+ dec.decodeValue(tWireType, reflect.ValueOf(wire))
if dec.err != nil {
return
}
@@ -161,7 +161,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
}
- value := reflect.NewValue(e)
+ value := reflect.ValueOf(e)
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
@@ -171,12 +171,18 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received, or it may be nil, which means the
-// value will be discarded.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+// DecodeValue reads the next value from the connection.
+// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
+// Otherwise, it stores the value into v. In that case, v must represent
+// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
+ if v.IsValid() {
+ if v.Kind() == reflect.Ptr && !v.IsNil() {
+ // That's okay, we'll store through the pointer.
+ } else if !v.CanSet() {
+ return os.ErrorString("gob: DecodeValue of unassignable value")
+ }
+ }
// Make sure we're single-threaded through here.
dec.mutex.Lock()
defer dec.mutex.Unlock()
@@ -185,7 +191,7 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
dec.err = nil
id := dec.decodeTypeSequence(false)
if dec.err == nil {
- dec.decodeValue(id, value)
+ dec.decodeValue(id, v)
}
return dec.err
}
diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go
index 613974a00..189086f52 100644
--- a/src/pkg/gob/doc.go
+++ b/src/pkg/gob/doc.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
/*
-The gob package manages streams of gobs - binary values exchanged between an
+Package gob manages streams of gobs - binary values exchanged between an
Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
arguments and results of remote procedure calls (RPCs) such as those provided by
package "rpc".
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index 36bde08aa..f9e691a2f 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -384,7 +384,7 @@ func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid ui
up := unsafe.Pointer(elemp)
if elemIndir > 0 {
if up = encIndirect(up, elemIndir); up == nil {
- errorf("gob: encodeArray: nil element")
+ errorf("encodeArray: nil element")
}
elemp = uintptr(up)
}
@@ -400,9 +400,9 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
v = reflect.Indirect(v)
}
if !v.IsValid() {
- errorf("gob: encodeReflectValue: nil element")
+ errorf("encodeReflectValue: nil element")
}
- op(nil, state, unsafe.Pointer(v.UnsafeAddr()))
+ op(nil, state, unsafe.Pointer(unsafeAddr(v)))
}
// encodeMap encodes a map as unsigned count followed by key:value pairs.
@@ -438,7 +438,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
ut := userType(iv.Elem().Type())
name, ok := concreteTypeToName[ut.base]
if !ok {
- errorf("gob: type not registered for interface: %s", ut.base)
+ errorf("type not registered for interface: %s", ut.base)
}
// Send the name.
state.encodeUint(uint64(len(name)))
@@ -555,7 +555,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
- v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
mv := reflect.Indirect(v)
if !state.sendZero && mv.Len() == 0 {
return
@@ -576,7 +576,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
// Interfaces transmit the name and contents of the concrete
// value they contain.
- v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
iv := reflect.Indirect(v)
if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
return
@@ -587,7 +587,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
}
}
if op == nil {
- errorf("gob enc: can't happen: encode type %s", rt.String())
+ errorf("can't happen: encode type %s", rt.String())
}
return &op, indir
}
@@ -599,7 +599,7 @@ func methodIndex(rt reflect.Type, method string) int {
return i
}
}
- errorf("gob: internal error: can't find method %s", method)
+ errorf("internal error: can't find method %s", method)
return 0
}
@@ -619,9 +619,9 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
var v reflect.Value
if ut.encIndir == -1 {
// Need to climb up one level to turn value into pointer.
- v = reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
+ v = reflect.ValueOf(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
} else {
- v = reflect.NewValue(unsafe.Unreflect(rt, p))
+ v = reflect.ValueOf(unsafe.Unreflect(rt, p))
}
state.update(i)
state.enc.encodeGobEncoder(state.b, v, methodIndex(rt, gobEncodeMethodName))
@@ -650,7 +650,7 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
wireFieldNum++
}
if srt.NumField() > 0 && len(engine.instr) == 0 {
- errorf("gob: type %s has no exported fields", rt)
+ errorf("type %s has no exported fields", rt)
}
engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0})
} else {
@@ -695,8 +695,8 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
value = reflect.Indirect(value)
}
if !ut.isGobEncoder && value.Type().Kind() == reflect.Struct {
- enc.encodeStruct(b, engine, value.UnsafeAddr())
+ enc.encodeStruct(b, engine, unsafeAddr(value))
} else {
- enc.encodeSingle(b, engine, value.UnsafeAddr())
+ enc.encodeSingle(b, engine, unsafeAddr(value))
}
}
diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go
index 928f3b244..65ee5bf67 100644
--- a/src/pkg/gob/encoder.go
+++ b/src/pkg/gob/encoder.go
@@ -97,7 +97,7 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp
// Id:
state.encodeInt(-int64(info.id))
// Type:
- enc.encode(state.b, reflect.NewValue(info.wire), wireTypeUserInfo)
+ enc.encode(state.b, reflect.ValueOf(info.wire), wireTypeUserInfo)
enc.writeMessage(w, state.b)
if enc.err != nil {
return
@@ -116,6 +116,9 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp
}
case reflect.Array, reflect.Slice:
enc.sendType(w, state, st.Elem())
+ case reflect.Map:
+ enc.sendType(w, state, st.Key())
+ enc.sendType(w, state, st.Elem())
}
return true
}
@@ -162,7 +165,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
// Encode transmits the data item represented by the empty interface value,
// guaranteeing that all necessary type information has been transmitted first.
func (enc *Encoder) Encode(e interface{}) os.Error {
- return enc.EncodeValue(reflect.NewValue(e))
+ return enc.EncodeValue(reflect.ValueOf(e))
}
// sendTypeDescriptor makes sure the remote side knows about this type.
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
index 3d5dfdb86..792afbd77 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/gob/encoder_test.go
@@ -170,7 +170,7 @@ func TestTypeToPtrType(t *testing.T) {
A int
}
t0 := Type0{7}
- t0p := (*Type0)(nil)
+ t0p := new(Type0)
if err := encAndDec(t0, t0p); err != nil {
t.Error(err)
}
@@ -339,7 +339,7 @@ func TestSingletons(t *testing.T) {
continue
}
// Get rid of the pointer in the rhs
- val := reflect.NewValue(test.out).Elem().Interface()
+ val := reflect.ValueOf(test.out).Elem().Interface()
if !reflect.DeepEqual(test.in, val) {
t.Errorf("decoding singleton: expected %v got %v", test.in, val)
}
@@ -514,3 +514,38 @@ func TestNestedInterfaces(t *testing.T) {
t.Fatalf("final value %d; expected %d", inner.A, 7)
}
}
+
+// The bugs keep coming. We forgot to send map subtypes before the map.
+
+type Bug1Elem struct {
+ Name string
+ Id int
+}
+
+type Bug1StructMap map[string]Bug1Elem
+
+func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) os.Error {
+ return nil
+}
+
+func TestMapBug1(t *testing.T) {
+ in := make(Bug1StructMap)
+ in["val1"] = Bug1Elem{"elem1", 1}
+ in["val2"] = Bug1Elem{"elem2", 2}
+
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(in)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ dec := NewDecoder(b)
+ out := make(Bug1StructMap)
+ err = dec.Decode(&out)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(in, out) {
+ t.Errorf("mismatch: %v %v", in, out)
+ }
+}
diff --git a/src/pkg/gob/error.go b/src/pkg/gob/error.go
index b053761fb..bfd38fc16 100644
--- a/src/pkg/gob/error.go
+++ b/src/pkg/gob/error.go
@@ -22,8 +22,9 @@ type gobError struct {
}
// errorf is like error but takes Printf-style arguments to construct an os.Error.
+// It always prefixes the message with "gob: ".
func errorf(format string, args ...interface{}) {
- error(fmt.Errorf(format, args...))
+ error(fmt.Errorf("gob: "+format, args...))
}
// error wraps the argument error and uses it as the argument to panic.
diff --git a/src/pkg/gob/gobencdec_test.go b/src/pkg/gob/gobencdec_test.go
index 012b09956..e94534f4c 100644
--- a/src/pkg/gob/gobencdec_test.go
+++ b/src/pkg/gob/gobencdec_test.go
@@ -24,6 +24,10 @@ type StringStruct struct {
s string // not an exported field
}
+type ArrayStruct struct {
+ a [8192]byte // not an exported field
+}
+
type Gobber int
type ValueGobber string // encodes with a value, decodes with a pointer.
@@ -74,6 +78,18 @@ func (g *StringStruct) GobDecode(data []byte) os.Error {
return nil
}
+func (a *ArrayStruct) GobEncode() ([]byte, os.Error) {
+ return a.a[:], nil
+}
+
+func (a *ArrayStruct) GobDecode(data []byte) os.Error {
+ if len(data) != len(a.a) {
+ return os.ErrorString("wrong length in array decode")
+ }
+ copy(a.a[:], data)
+ return nil
+}
+
func (g *Gobber) GobEncode() ([]byte, os.Error) {
return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
}
@@ -138,6 +154,16 @@ type GobTestIndirectEncDec struct {
G ***StringStruct // indirections to the receiver.
}
+type GobTestArrayEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ A ArrayStruct // not a pointer.
+}
+
+type GobTestIndirectArrayEncDec struct {
+ X int // guarantee we have something in common with GobTest*
+ A ***ArrayStruct // indirections to a large receiver.
+}
+
func TestGobEncoderField(t *testing.T) {
b := new(bytes.Buffer)
// First a field that's a structure.
@@ -216,6 +242,64 @@ func TestGobEncoderIndirectField(t *testing.T) {
}
}
+// Test with a large field with methods.
+func TestGobEncoderArrayField(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ var a GobTestArrayEncDec
+ a.X = 17
+ for i := range a.A.a {
+ a.A.a[i] = byte(i)
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestArrayEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ for i, v := range x.A.a {
+ if v != byte(i) {
+ t.Errorf("expected %x got %x", byte(i), v)
+ break
+ }
+ }
+}
+
+// Test an indirection to a large field with methods.
+func TestGobEncoderIndirectArrayField(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ var a GobTestIndirectArrayEncDec
+ a.X = 17
+ var array ArrayStruct
+ ap := &array
+ app := &ap
+ a.A = &app
+ for i := range array.a {
+ array.a[i] = byte(i)
+ }
+ err := enc.Encode(a)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTestIndirectArrayEncDec)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ for i, v := range (***x.A).a {
+ if v != byte(i) {
+ t.Errorf("expected %x got %x", byte(i), v)
+ break
+ }
+ }
+}
+
// As long as the fields have the same name and implement the
// interface, we can cross-connect them. Not sure it's useful
// and may even be bad but it works and it's hard to prevent
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index 8fd174841..c5b8fb5d9 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -74,8 +74,8 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
}
ut.indir++
}
- ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderCheck)
- ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderCheck)
+ ut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType)
+ ut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType)
userTypeCache[rt] = ut
return
}
@@ -85,32 +85,16 @@ const (
gobDecodeMethodName = "GobDecode"
)
-// implements returns whether the type implements the interface, as encoded
-// in the check function.
-func implements(typ reflect.Type, check func(typ reflect.Type) bool) bool {
- if typ.NumMethod() == 0 { // avoid allocations etc. unless there's some chance
- return false
- }
- return check(typ)
-}
-
-// gobEncoderCheck makes the type assertion a boolean function.
-func gobEncoderCheck(typ reflect.Type) bool {
- _, ok := reflect.Zero(typ).Interface().(GobEncoder)
- return ok
-}
-
-// gobDecoderCheck makes the type assertion a boolean function.
-func gobDecoderCheck(typ reflect.Type) bool {
- _, ok := reflect.Zero(typ).Interface().(GobDecoder)
- return ok
-}
+var (
+ gobEncoderInterfaceType = reflect.TypeOf(new(GobEncoder)).Elem()
+ gobDecoderInterfaceType = reflect.TypeOf(new(GobDecoder)).Elem()
+)
// implementsInterface reports whether the type implements the
-// interface. (The actual check is done through the provided function.)
+// gobEncoder/gobDecoder interface.
// It also returns the number of indirections required to get to the
// implementation.
-func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (success bool, indir int8) {
+func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir int8) {
if typ == nil {
return
}
@@ -118,7 +102,7 @@ func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (s
// The type might be a pointer and we need to keep
// dereferencing to the base type until we find an implementation.
for {
- if implements(rt, check) {
+ if rt.Implements(gobEncDecType) {
return true, indir
}
if p := rt; p.Kind() == reflect.Ptr {
@@ -134,7 +118,7 @@ func implementsInterface(typ reflect.Type, check func(typ reflect.Type) bool) (s
// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
if typ.Kind() != reflect.Ptr {
// Not a pointer, but does the pointer work?
- if implements(reflect.PtrTo(typ), check) {
+ if reflect.PtrTo(typ).Implements(gobEncDecType) {
return true, -1
}
}
@@ -243,18 +227,18 @@ var (
)
// Predefined because it's needed by the Decoder
-var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
+var tWireType = mustGetTypeInfo(reflect.TypeOf(wireType{})).id
var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
func init() {
// Some magic numbers to make sure there are no surprises.
checkId(16, tWireType)
- checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
- checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
- checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
- checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
- checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
- checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
+ checkId(17, mustGetTypeInfo(reflect.TypeOf(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.TypeOf(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.TypeOf(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.TypeOf(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.TypeOf(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.TypeOf(mapType{})).id)
builtinIdToType = make(map[typeId]gobType)
for k, v := range idToType {
@@ -268,7 +252,7 @@ func init() {
}
nextId = firstUserId
registerBasics()
- wireTypeUserInfo = userType(reflect.Typeof((*wireType)(nil)))
+ wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
}
// Array type
@@ -569,7 +553,7 @@ func checkId(want, got typeId) {
// used for building the basic types; called only from init(). the incoming
// interface always refers to a pointer.
func bootstrapType(name string, e interface{}, expect typeId) typeId {
- rt := reflect.Typeof(e).Elem()
+ rt := reflect.TypeOf(e).Elem()
_, present := types[rt]
if present {
panic("bootstrap type already present: " + name + ", " + rt.String())
@@ -723,7 +707,7 @@ func RegisterName(name string, value interface{}) {
// reserved for nil
panic("attempt to register empty name")
}
- base := userType(reflect.Typeof(value)).base
+ base := userType(reflect.TypeOf(value)).base
// Check for incompatible duplicates.
if t, ok := nameToConcreteType[name]; ok && t != base {
panic("gob: registering duplicate types for " + name)
@@ -732,7 +716,7 @@ func RegisterName(name string, value interface{}) {
panic("gob: registering duplicate names for " + base.String())
}
// Store the name and type provided by the user....
- nameToConcreteType[name] = reflect.Typeof(value)
+ nameToConcreteType[name] = reflect.TypeOf(value)
// but the flattened type in the type table, since that's what decode needs.
concreteTypeToName[base] = name
}
@@ -745,7 +729,7 @@ func RegisterName(name string, value interface{}) {
// between types and names is not a bijection.
func Register(value interface{}) {
// Default to printed representation for unnamed types
- rt := reflect.Typeof(value)
+ rt := reflect.TypeOf(value)
name := rt.String()
// But for named types (or pointers to them), qualify with import path.
diff --git a/src/pkg/gob/type_test.go b/src/pkg/gob/type_test.go
index ffd1345e5..411ffb797 100644
--- a/src/pkg/gob/type_test.go
+++ b/src/pkg/gob/type_test.go
@@ -47,15 +47,15 @@ func TestBasic(t *testing.T) {
// Reregister some basic types to check registration is idempotent.
func TestReregistration(t *testing.T) {
- newtyp := getTypeUnlocked("int", reflect.Typeof(int(0)))
+ newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
if newtyp != tInt.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
- newtyp = getTypeUnlocked("uint", reflect.Typeof(uint(0)))
+ newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
if newtyp != tUint.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
- newtyp = getTypeUnlocked("string", reflect.Typeof("hello"))
+ newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
if newtyp != tString.gobType() {
t.Errorf("reregistration of %s got new type", newtyp.string())
}
@@ -63,18 +63,18 @@ func TestReregistration(t *testing.T) {
func TestArrayType(t *testing.T) {
var a3 [3]int
- a3int := getTypeUnlocked("foo", reflect.Typeof(a3))
- newa3int := getTypeUnlocked("bar", reflect.Typeof(a3))
+ a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
+ newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
if a3int != newa3int {
t.Errorf("second registration of [3]int creates new type")
}
var a4 [4]int
- a4int := getTypeUnlocked("goo", reflect.Typeof(a4))
+ a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
if a3int == a4int {
t.Errorf("registration of [3]int creates same type as [4]int")
}
var b3 [3]bool
- a3bool := getTypeUnlocked("", reflect.Typeof(b3))
+ a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
if a3int == a3bool {
t.Errorf("registration of [3]bool creates same type as [3]int")
}
@@ -87,14 +87,14 @@ func TestArrayType(t *testing.T) {
func TestSliceType(t *testing.T) {
var s []int
- sint := getTypeUnlocked("slice", reflect.Typeof(s))
+ sint := getTypeUnlocked("slice", reflect.TypeOf(s))
var news []int
- newsint := getTypeUnlocked("slice1", reflect.Typeof(news))
+ newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
if sint != newsint {
t.Errorf("second registration of []int creates new type")
}
var b []bool
- sbool := getTypeUnlocked("", reflect.Typeof(b))
+ sbool := getTypeUnlocked("", reflect.TypeOf(b))
if sbool == sint {
t.Errorf("registration of []bool creates same type as []int")
}
@@ -107,14 +107,14 @@ func TestSliceType(t *testing.T) {
func TestMapType(t *testing.T) {
var m map[string]int
- mapStringInt := getTypeUnlocked("map", reflect.Typeof(m))
+ mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
var newm map[string]int
- newMapStringInt := getTypeUnlocked("map1", reflect.Typeof(newm))
+ newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
if mapStringInt != newMapStringInt {
t.Errorf("second registration of map[string]int creates new type")
}
var b map[string]bool
- mapStringBool := getTypeUnlocked("", reflect.Typeof(b))
+ mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
if mapStringBool == mapStringInt {
t.Errorf("registration of map[string]bool creates same type as map[string]int")
}
@@ -143,7 +143,7 @@ type Foo struct {
}
func TestStructType(t *testing.T) {
- sstruct := getTypeUnlocked("Foo", reflect.Typeof(Foo{}))
+ sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
str := sstruct.string()
// If we can print it correctly, we built it correctly.
expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"