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.go96
1 files changed, 61 insertions, 35 deletions
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index 2fbcf68b3..659ab68d2 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -17,6 +17,11 @@ import (
"unsafe";
)
+var (
+ ErrRange = os.ErrorString("gob: internal error: field numbers out of bounds");
+ ErrNotStruct = os.ErrorString("gob: TODO: can only handle structs")
+)
+
// The global execution state of an instance of the decoder.
type decodeState struct {
b *bytes.Buffer;
@@ -342,7 +347,8 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
}
fieldnum := state.fieldnum + delta;
if fieldnum >= len(engine.instr) {
- panicln("TODO(r): field number out of range", fieldnum, len(engine.instr));
+ state.err = ErrRange;
+ break;
}
instr := &engine.instr[fieldnum];
p := unsafe.Pointer(basep+instr.offset);
@@ -452,11 +458,11 @@ var decIgnoreOpMap = map[TypeId] decOp {
tString: ignoreUint8Array,
}
-func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine
+func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error)
// Return the decoding op for the base type under rt and
// the indirection count to reach it.
-func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
+func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
typ, indir := indirect(rt);
op, ok := decOpMap[reflect.Typeof(typ)];
if !ok {
@@ -468,21 +474,30 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
break;
}
elemId := wireId.gobType().(*sliceType).Elem;
- elemOp, elemIndir := decOpFor(elemId, t.Elem());
+ elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
+ if err != nil {
+ return nil, 0, err
+ }
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir);
};
case *reflect.ArrayType:
elemId := wireId.gobType().(*arrayType).Elem;
- elemOp, elemIndir := decOpFor(elemId, t.Elem());
+ elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
+ if err != nil {
+ return nil, 0, err
+ }
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir);
};
case *reflect.StructType:
// Generate a closure that calls out to the engine for the nested type.
- enginePtr := getDecEnginePtr(wireId, typ);
+ enginePtr, err := getDecEnginePtr(wireId, typ);
+ if err != nil {
+ return nil, 0, err
+ }
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through info to delay evaluation for recursive structs
state.err = decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
@@ -490,27 +505,33 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int) {
}
}
if op == nil {
- panicln("decode can't handle type", rt.String());
+ return nil, 0, os.ErrorString("gob: decode can't handle type " + rt.String());
}
- return op, indir
+ return op, indir, nil
}
// Return the decoding op for a field that has no destination.
-func decIgnoreOpFor(wireId TypeId) decOp {
+func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
op, ok := decIgnoreOpMap[wireId];
if !ok {
// Special cases
switch t := wireId.gobType().(type) {
case *sliceType:
elemId := wireId.gobType().(*sliceType).Elem;
- elemOp := decIgnoreOpFor(elemId);
+ elemOp, err := decIgnoreOpFor(elemId);
+ if err != nil {
+ return nil, err
+ }
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
state.err = ignoreSlice(state, elemOp);
};
case *arrayType:
elemId := wireId.gobType().(*arrayType).Elem;
- elemOp := decIgnoreOpFor(elemId);
+ elemOp, err := decIgnoreOpFor(elemId);
+ if err != nil {
+ return nil, err
+ }
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
state.err = ignoreArray(state, elemOp, t.Len);
};
@@ -520,9 +541,9 @@ func decIgnoreOpFor(wireId TypeId) decOp {
}
}
if op == nil {
- panicln("decode can't handle type", wireId.gobType().String());
+ return nil, os.ErrorString("ignore can't handle type " + wireId.String());
}
- return op;
+ return op, nil;
}
// Are these two gob Types compatible?
@@ -588,48 +609,46 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
return true;
}
-func compileDec(wireId TypeId, rt reflect.Type) *decEngine {
+func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error) {
srt, ok1 := rt.(*reflect.StructType);
wireStruct, ok2 := wireId.gobType().(*structType);
if !ok1 || !ok2 {
- panicln("gob: TODO: can't handle non-structs");
+ return nil, ErrNotStruct
}
- engine := new(decEngine);
+ engine = new(decEngine);
engine.instr = make([]decInstr, len(wireStruct.field));
// Loop over the fields of the wire type.
for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
wireField := wireStruct.field[fieldnum];
// Find the field of the local type with the same name.
- // TODO: put this as a method in reflect
- var localField reflect.StructField;
- for lfn := 0; lfn < srt.NumField(); lfn++ {
- if srt.Field(lfn).Name == wireField.name {
- localField = srt.Field(lfn);
- break;
- }
- }
+ localField, present := srt.FieldByName(wireField.name);
// TODO(r): anonymous names
- if localField.Anonymous || localField.Name == "" {
+ if !present || localField.Anonymous {
println("no matching field", wireField.name, "in type", wireId.String());
- op := decIgnoreOpFor(wireField.typeId);
+ op, err := decIgnoreOpFor(wireField.typeId);
+ if err != nil {
+ return nil, err
+ }
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
continue;
}
if !compatibleType(localField.Type, wireField.typeId) {
- panicln("TODO: wrong type for field", wireField.name, "in type", wireId.String());
+ return nil, os.ErrorString("gob: TODO: wrong type for field " + wireField.name + " in type " + wireId.String());
+ }
+ op, indir, err := decOpFor(wireField.typeId, localField.Type);
+ if err != nil {
+ return nil, err
}
- op, indir := decOpFor(wireField.typeId, localField.Type);
engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset)};
engine.numInstr++;
}
- return engine;
+ return;
}
// typeLock must be held.
-func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine {
+func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
info := getTypeInfo(rt); // TODO: eliminate this; creates a gobType you don't need.
- var enginePtr **decEngine;
var ok bool;
if enginePtr, ok = info.decoderPtr[wireId]; !ok {
if info.typeId.gobType() == nil {
@@ -639,9 +658,12 @@ func getDecEnginePtr(wireId TypeId, rt reflect.Type) **decEngine {
// mark this engine as underway before compiling to handle recursive types.
enginePtr = new(*decEngine);
info.decoderPtr[wireId] = enginePtr;
- *enginePtr = compileDec(wireId, rt);
+ *enginePtr, err = compileDec(wireId, rt);
+ if err != nil {
+ info.decoderPtr[wireId] = nil, false;
+ }
}
- return enginePtr
+ return
}
func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
@@ -657,11 +679,15 @@ func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
return os.ErrorString("gob: decode can't handle " + rt.String())
}
typeLock.Lock();
- engine := *getDecEnginePtr(wireId, rt);
+ enginePtr, err := getDecEnginePtr(wireId, rt);
typeLock.Unlock();
+ if err != nil {
+ return err
+ }
+ engine := *enginePtr;
if engine.numInstr == 0 && st.NumField() > 0 {
path, name := rt.Name();
- return os.ErrorString("no fields matched compiling decoder for " + name)
+ return os.ErrorString("type mismatch: no fields matched compiling decoder for " + name)
}
return decodeStruct(engine, rt.(*reflect.StructType), b, uintptr(v.Addr()), 0);
}