summaryrefslogtreecommitdiff
path: root/src/pkg/gob/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/gob/decode.go')
-rw-r--r--src/pkg/gob/decode.go126
1 files changed, 70 insertions, 56 deletions
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()
+}