diff options
Diffstat (limited to 'src/pkg/gob/decode.go')
-rw-r--r-- | src/pkg/gob/decode.go | 126 |
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() +} |