]> Cypherpunks repositories - gostls13.git/commitdiff
- clean up code creating keys for type maps
authorRob Pike <r@golang.org>
Tue, 28 Jul 2009 19:59:39 +0000 (12:59 -0700)
committerRob Pike <r@golang.org>
Tue, 28 Jul 2009 19:59:39 +0000 (12:59 -0700)
- derive int, uint, float, uintptr decoders based on their size
- add overflow checks in decode

R=rsc
DELTA=407  (281 added, 44 deleted, 82 changed)
OCL=32286
CL=32290

src/pkg/gob/codec_test.go
src/pkg/gob/decode.go
src/pkg/gob/encode.go
src/pkg/gob/encoder.go
src/pkg/gob/type.go

index 848a8719473fd160d1e671e05ca971a560a731b9..66d6b01ec530668745ac6db95d4d1791211bfc22 100644 (file)
@@ -7,6 +7,7 @@ package gob
 import (
        "bytes";
        "gob";
+       "math";
        "os";
        "reflect";
        "strings";
@@ -347,21 +348,22 @@ func newdecodeState(data []byte) *decodeState {
 // Test instruction execution for decoding.
 // Do not run the machine yet; instead do individual instructions crafted by hand.
 func TestScalarDecInstructions(t *testing.T) {
+       ovfl := os.ErrorString("overflow");
 
        // bool
        {
                var data struct { a bool };
-               instr := &decInstr{ decBool, 6, 0, 0 };
+               instr := &decInstr{ decBool, 6, 0, 0, ovfl };
                state := newdecodeState(boolResult);
                execDec("bool", instr, state, t, unsafe.Pointer(&data));
                if data.a != true {
-                       t.Errorf("int a = %v not true", data.a)
+                       t.Errorf("bool a = %v not true", data.a)
                }
        }
        // int
        {
                var data struct { a int };
-               instr := &decInstr{ decInt, 6, 0, 0 };
+               instr := &decInstr{ decOpMap[valueKind(data.a)], 6, 0, 0, ovfl };
                state := newdecodeState(signedResult);
                execDec("int", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
@@ -372,139 +374,150 @@ func TestScalarDecInstructions(t *testing.T) {
        // uint
        {
                var data struct { a uint };
-               instr := &decInstr{ decUint, 6, 0, 0 };
+               instr := &decInstr{ decOpMap[valueKind(data.a)], 6, 0, 0, ovfl };
                state := newdecodeState(unsignedResult);
                execDec("uint", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("uint a = %v not 17", data.a)
                }
        }
 
        // int8
        {
                var data struct { a int8 };
-               instr := &decInstr{ decInt8, 6, 0, 0 };
+               instr := &decInstr{ decInt8, 6, 0, 0, ovfl };
                state := newdecodeState(signedResult);
                execDec("int8", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("int8 a = %v not 17", data.a)
                }
        }
 
        // uint8
        {
                var data struct { a uint8 };
-               instr := &decInstr{ decUint8, 6, 0, 0 };
+               instr := &decInstr{ decUint8, 6, 0, 0, ovfl };
                state := newdecodeState(unsignedResult);
                execDec("uint8", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("uint8 a = %v not 17", data.a)
                }
        }
 
        // int16
        {
                var data struct { a int16 };
-               instr := &decInstr{ decInt16, 6, 0, 0 };
+               instr := &decInstr{ decInt16, 6, 0, 0, ovfl };
                state := newdecodeState(signedResult);
                execDec("int16", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("int16 a = %v not 17", data.a)
                }
        }
 
        // uint16
        {
                var data struct { a uint16 };
-               instr := &decInstr{ decUint16, 6, 0, 0 };
+               instr := &decInstr{ decUint16, 6, 0, 0, ovfl };
                state := newdecodeState(unsignedResult);
                execDec("uint16", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("uint16 a = %v not 17", data.a)
                }
        }
 
        // int32
        {
                var data struct { a int32 };
-               instr := &decInstr{ decInt32, 6, 0, 0 };
+               instr := &decInstr{ decInt32, 6, 0, 0, ovfl };
                state := newdecodeState(signedResult);
                execDec("int32", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("int32 a = %v not 17", data.a)
                }
        }
 
        // uint32
        {
                var data struct { a uint32 };
-               instr := &decInstr{ decUint32, 6, 0, 0 };
+               instr := &decInstr{ decUint32, 6, 0, 0, ovfl };
                state := newdecodeState(unsignedResult);
                execDec("uint32", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("uint32 a = %v not 17", data.a)
+               }
+       }
+
+       // uintptr
+       {
+               var data struct { a uintptr };
+               instr := &decInstr{ decOpMap[valueKind(data.a)], 6, 0, 0, ovfl };
+               state := newdecodeState(unsignedResult);
+               execDec("uintptr", instr, state, t, unsafe.Pointer(&data));
+               if data.a != 17 {
+                       t.Errorf("uintptr a = %v not 17", data.a)
                }
        }
 
        // int64
        {
                var data struct { a int64 };
-               instr := &decInstr{ decInt64, 6, 0, 0 };
+               instr := &decInstr{ decInt64, 6, 0, 0, ovfl };
                state := newdecodeState(signedResult);
                execDec("int64", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("int64 a = %v not 17", data.a)
                }
        }
 
        // uint64
        {
                var data struct { a uint64 };
-               instr := &decInstr{ decUint64, 6, 0, 0 };
+               instr := &decInstr{ decUint64, 6, 0, 0, ovfl };
                state := newdecodeState(unsignedResult);
                execDec("uint64", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("uint64 a = %v not 17", data.a)
                }
        }
 
        // float
        {
                var data struct { a float };
-               instr := &decInstr{ decFloat, 6, 0, 0 };
+               instr := &decInstr{ decOpMap[valueKind(data.a)], 6, 0, 0, ovfl };
                state := newdecodeState(floatResult);
                execDec("float", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("float a = %v not 17", data.a)
                }
        }
 
        // float32
        {
                var data struct { a float32 };
-               instr := &decInstr{ decFloat32, 6, 0, 0 };
+               instr := &decInstr{ decFloat32, 6, 0, 0, ovfl };
                state := newdecodeState(floatResult);
                execDec("float32", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("float32 a = %v not 17", data.a)
                }
        }
 
        // float64
        {
                var data struct { a float64 };
-               instr := &decInstr{ decFloat64, 6, 0, 0 };
+               instr := &decInstr{ decFloat64, 6, 0, 0, ovfl };
                state := newdecodeState(floatResult);
                execDec("float64", instr, state, t, unsafe.Pointer(&data));
                if data.a != 17 {
-                       t.Errorf("int a = %v not 17", data.a)
+                       t.Errorf("float64 a = %v not 17", data.a)
                }
        }
 
        // bytes == []uint8
        {
                var data struct { a []byte };
-               instr := &decInstr{ decUint8Array, 6, 0, 0 };
+               instr := &decInstr{ decUint8Array, 6, 0, 0, ovfl };
                state := newdecodeState(bytesResult);
                execDec("bytes", instr, state, t, unsafe.Pointer(&data));
                if string(data.a) != "hello" {
@@ -515,7 +528,7 @@ func TestScalarDecInstructions(t *testing.T) {
        // string
        {
                var data struct { a string };
-               instr := &decInstr{ decString, 6, 0, 0 };
+               instr := &decInstr{ decString, 6, 0, 0, ovfl };
                state := newdecodeState(bytesResult);
                execDec("bytes", instr, state, t, unsafe.Pointer(&data));
                if data.a != "hello" {
@@ -559,6 +572,157 @@ func TestEndToEnd(t *testing.T) {
        }
 }
 
+func TestOverflow(t *testing.T) {
+       type inputT struct {
+               maxi    int64;
+               mini    int64;
+               maxu    uint64;
+               maxf    float64;
+               minf    float64;
+       }
+       var it inputT;
+       var err os.Error;
+       id := getTypeInfo(reflect.Typeof(it)).id;
+       b := new(bytes.Buffer);
+
+       // int8
+       b.Reset();
+       it = inputT {
+               maxi: math.MaxInt8 + 1,
+       };
+       type outi8 struct {
+               maxi int8;
+               mini int8;
+       }
+       var o1 outi8;
+       encode(b, it);
+       err = decode(b, id, &o1);
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int8:", err)
+       }
+       it = inputT {
+               mini: math.MinInt8 - 1,
+       };
+       b.Reset();
+       encode(b, it);
+       err = decode(b, id, &o1);
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int8:", err)
+       }
+
+       // int16
+       b.Reset();
+       it = inputT {
+               maxi: math.MaxInt16 + 1,
+       };
+       type outi16 struct {
+               maxi int16;
+               mini int16;
+       }
+       var o2 outi16;
+       encode(b, it);
+       err = decode(b, id, &o2);
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int16:", err)
+       }
+       it = inputT {
+               mini: math.MinInt16 - 1,
+       };
+       b.Reset();
+       encode(b, it);
+       err = decode(b, id, &o2);
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int16:", err)
+       }
+
+       // int32
+       b.Reset();
+       it = inputT {
+               maxi: math.MaxInt32 + 1,
+       };
+       type outi32 struct {
+               maxi int32;
+               mini int32;
+       }
+       var o3 outi32;
+       encode(b, it);
+       err = decode(b, id, &o3);
+       if err == nil || err.String() != `value for "maxi" out of range` {
+               t.Error("wrong overflow error for int32:", err)
+       }
+       it = inputT {
+               mini: math.MinInt32 - 1,
+       };
+       b.Reset();
+       encode(b, it);
+       err = decode(b, id, &o3);
+       if err == nil || err.String() != `value for "mini" out of range` {
+               t.Error("wrong underflow error for int32:", err)
+       }
+
+       // uint8
+       b.Reset();
+       it = inputT {
+               maxu: math.MaxUint8 + 1,
+       };
+       type outu8 struct {
+               maxu uint8;
+       }
+       var o4 outu8;
+       encode(b, it);
+       err = decode(b, id, &o4);
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint8:", err)
+       }
+
+       // uint16
+       b.Reset();
+       it = inputT {
+               maxu: math.MaxUint16 + 1,
+       };
+       type outu16 struct {
+               maxu uint16;
+       }
+       var o5 outu16;
+       encode(b, it);
+       err = decode(b, id, &o5);
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint16:", err)
+       }
+
+       // uint32
+       b.Reset();
+       it = inputT {
+               maxu: math.MaxUint32 + 1,
+       };
+       type outu32 struct {
+               maxu uint32;
+       }
+       var o6 outu32;
+       encode(b, it);
+       err = decode(b, id, &o6);
+       if err == nil || err.String() != `value for "maxu" out of range` {
+               t.Error("wrong overflow error for uint32:", err)
+       }
+
+       // float32
+       b.Reset();
+       it = inputT {
+               maxf: math.MaxFloat32 * 2,
+       };
+       type outf32 struct {
+               maxf float32;
+               minf float32;
+       }
+       var o7 outf32;
+       encode(b, it);
+       err = decode(b, id, &o7);
+       if err == nil || err.String() != `value for "maxf" out of range` {
+               t.Error("wrong overflow error for float32:", err)
+       }
+}
+
+
 func TestNesting(t *testing.T) {
        type RT struct {
                a string;
index 7e439e8e7a0169c1e37440c56b9a479e416d5ba8..17afca607216db9284c00a6cbc619070c40f88b4 100644 (file)
@@ -29,6 +29,10 @@ type decodeState struct {
        fieldnum        int;    // the last field number read.
 }
 
+func overflow(name string) os.ErrorString {
+       return os.ErrorString(`value for "` + name + `" out of range`); 
+}
+
 // decodeUintReader reads an encoded unsigned integer from an io.Reader.
 // Used only by the Decoder to read the message length.
 func decodeUintReader(r io.Reader, oneByte []byte) (x uint64, err os.Error) {
@@ -50,6 +54,7 @@ func decodeUintReader(r io.Reader, oneByte []byte) (x uint64, err os.Error) {
 
 // decodeUint reads an encoded unsigned integer from state.r.
 // Sets state.err.  If state.err is already non-nil, it does nothing.
+// Does not check for overflow.
 func decodeUint(state *decodeState) (x uint64) {
        if state.err != nil {
                return
@@ -71,6 +76,7 @@ func decodeUint(state *decodeState) (x uint64) {
 
 // decodeInt reads an encoded signed integer from state.r.
 // Sets state.err.  If state.err is already non-nil, it does nothing.
+// Does not check for overflow.
 func decodeInt(state *decodeState) int64 {
        x := decodeUint(state);
        if state.err != nil {
@@ -91,6 +97,7 @@ type decInstr struct {
        field           int;    // field number of the wire type
        indir   int;    // how many pointer indirections to reach the value in the struct
        offset  uintptr;        // offset in the structure of the field to encode
+       ovfl    os.ErrorString; // error message for overflow/underflow (for arrays, of the elements)
 }
 
 // Since the encoder writes no zeros, if we arrive at a decoder we have
@@ -126,26 +133,6 @@ func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
        *(*bool)(p) = decodeInt(state) != 0;
 }
 
-func decInt(i *decInstr, state *decodeState, p unsafe.Pointer) {
-       if i.indir > 0 {
-               if *(*unsafe.Pointer)(p) == nil {
-                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int));
-               }
-               p = *(*unsafe.Pointer)(p);
-       }
-       *(*int)(p) = int(decodeInt(state));
-}
-
-func decUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
-       if i.indir > 0 {
-               if *(*unsafe.Pointer)(p) == nil {
-                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint));
-               }
-               p = *(*unsafe.Pointer)(p);
-       }
-       *(*uint)(p) = uint(decodeUint(state));
-}
-
 func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
        if i.indir > 0 {
                if *(*unsafe.Pointer)(p) == nil {
@@ -153,7 +140,12 @@ func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*int8)(p) = int8(decodeInt(state));
+       v := decodeInt(state);
+       if v < math.MinInt8 || math.MaxInt8 < v {
+               state.err = i.ovfl
+       } else {
+               *(*int8)(p) = int8(v)
+       }
 }
 
 func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -163,7 +155,12 @@ func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*uint8)(p) = uint8(decodeUint(state));
+       v := decodeUint(state);
+       if math.MaxUint8 < v {
+               state.err = i.ovfl
+       } else {
+               *(*uint8)(p) = uint8(v)
+       }
 }
 
 func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -173,7 +170,12 @@ func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*int16)(p) = int16(decodeInt(state));
+       v := decodeInt(state);
+       if v < math.MinInt16 || math.MaxInt16 < v {
+               state.err = i.ovfl
+       } else {
+               *(*int16)(p) = int16(v)
+       }
 }
 
 func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -183,7 +185,12 @@ func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*uint16)(p) = uint16(decodeUint(state));
+       v := decodeUint(state);
+       if math.MaxUint16 < v {
+               state.err = i.ovfl
+       } else {
+               *(*uint16)(p) = uint16(v)
+       }
 }
 
 func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -193,7 +200,12 @@ func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*int32)(p) = int32(decodeInt(state));
+       v := decodeInt(state);
+       if v < math.MinInt32 || math.MaxInt32 < v {
+               state.err = i.ovfl
+       } else {
+               *(*int32)(p) = int32(v)
+       }
 }
 
 func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -203,7 +215,12 @@ func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*uint32)(p) = uint32(decodeUint(state));
+       v := decodeUint(state);
+       if math.MaxUint32 < v {
+               state.err = i.ovfl
+       } else {
+               *(*uint32)(p) = uint32(v)
+       }
 }
 
 func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -226,16 +243,6 @@ func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
        *(*uint64)(p) = uint64(decodeUint(state));
 }
 
-func decUintptr(i *decInstr, state *decodeState, p unsafe.Pointer) {
-       if i.indir > 0 {
-               if *(*unsafe.Pointer)(p) == nil {
-                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uintptr));
-               }
-               p = *(*unsafe.Pointer)(p);
-       }
-       *(*uintptr)(p) = uintptr(decodeUint(state));
-}
-
 // Floating-point numbers are transmitted as uint64s holding the bits
 // of the underlying representation.  They are sent byte-reversed, with
 // the exponent end coming out first, so integer floating point numbers
@@ -251,16 +258,6 @@ func floatFromBits(u uint64) float64 {
        return math.Float64frombits(v);
 }
 
-func decFloat(i *decInstr, state *decodeState, p unsafe.Pointer) {
-       if i.indir > 0 {
-               if *(*unsafe.Pointer)(p) == nil {
-                       *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float));
-               }
-               p = *(*unsafe.Pointer)(p);
-       }
-       *(*float)(p) = float(floatFromBits(uint64(decodeUint(state))));
-}
-
 func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
        if i.indir > 0 {
                if *(*unsafe.Pointer)(p) == nil {
@@ -268,7 +265,16 @@ func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
                }
                p = *(*unsafe.Pointer)(p);
        }
-       *(*float32)(p) = float32(floatFromBits(uint64(decodeUint(state))));
+       v := floatFromBits(decodeUint(state));
+       av := v;
+       if av < 0 {
+               av = -av
+       }
+       if math.MaxFloat32 < av {       // underflow is OK
+               state.err = i.ovfl
+       } else {
+               *(*float32)(p) = float32(v)
+       }
 }
 
 func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -386,8 +392,8 @@ func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
        return state.err
 }
 
-func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int) os.Error {
-       instr := &decInstr{elemOp, 0, elemIndir, 0};
+func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) os.Error {
+       instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl};
        for i := 0; i < length && state.err == nil; i++ {
                up := unsafe.Pointer(p);
                if elemIndir > 1 {
@@ -399,7 +405,7 @@ func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uint
        return state.err
 }
 
-func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int) os.Error {
+func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) os.Error {
        if indir > 0 {
                up := unsafe.Pointer(p);
                if *(*unsafe.Pointer)(up) == nil {
@@ -413,11 +419,11 @@ func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp
        if n := decodeUint(state); n != uint64(length) {
                return os.ErrorString("gob: length mismatch in decodeArray");
        }
-       return decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir);
+       return decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl);
 }
 
 func ignoreArrayHelper(state *decodeState, elemOp decOp, length int) os.Error {
-       instr := &decInstr{elemOp, 0, 0, 0};
+       instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")};
        for i := 0; i < length && state.err == nil; i++ {
                elemOp(instr, state, nil);
        }
@@ -431,7 +437,7 @@ func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error {
        return ignoreArrayHelper(state, elemOp, length);
 }
 
-func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int) os.Error {
+func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) os.Error {
        length := uintptr(decodeUint(state));
        if indir > 0 {
                up := unsafe.Pointer(p);
@@ -448,7 +454,7 @@ func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp
        hdrp.Data = uintptr(unsafe.Pointer(&data[0]));
        hdrp.Len = int(length);
        hdrp.Cap = int(length);
-       return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, int(length), elemIndir);
+       return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, int(length), elemIndir, ovfl);
 }
 
 func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
@@ -456,22 +462,18 @@ func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
 }
 
 var decOpMap = map[reflect.Type] decOp {
-       reflect.Typeof((*reflect.BoolType)(nil)): decBool,
-       reflect.Typeof((*reflect.IntType)(nil)): decInt,
-       reflect.Typeof((*reflect.Int8Type)(nil)): decInt8,
-       reflect.Typeof((*reflect.Int16Type)(nil)): decInt16,
-       reflect.Typeof((*reflect.Int32Type)(nil)): decInt32,
-       reflect.Typeof((*reflect.Int64Type)(nil)): decInt64,
-       reflect.Typeof((*reflect.UintType)(nil)): decUint,
-       reflect.Typeof((*reflect.Uint8Type)(nil)): decUint8,
-       reflect.Typeof((*reflect.Uint16Type)(nil)): decUint16,
-       reflect.Typeof((*reflect.Uint32Type)(nil)): decUint32,
-       reflect.Typeof((*reflect.Uint64Type)(nil)): decUint64,
-       reflect.Typeof((*reflect.UintptrType)(nil)): decUintptr,
-       reflect.Typeof((*reflect.FloatType)(nil)): decFloat,
-       reflect.Typeof((*reflect.Float32Type)(nil)): decFloat32,
-       reflect.Typeof((*reflect.Float64Type)(nil)): decFloat64,
-       reflect.Typeof((*reflect.StringType)(nil)): decString,
+       valueKind(false): decBool,
+       valueKind(int8(0)): decInt8,
+       valueKind(int16(0)): decInt16,
+       valueKind(int32(0)): decInt32,
+       valueKind(int64(0)): decInt64,
+       valueKind(uint8(0)): decUint8,
+       valueKind(uint16(0)): decUint16,
+       valueKind(uint32(0)): decUint32,
+       valueKind(uint64(0)): decUint64,
+       valueKind(float32(0)): decFloat32,
+       valueKind(float64(0)): decFloat64,
+       valueKind("x"): decString,
 }
 
 var decIgnoreOpMap = map[typeId] decOp {
@@ -488,34 +490,38 @@ func getIgnoreEnginePtr(wireId typeId) (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, os.Error) {
+func decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int, os.Error) {
        typ, indir := indirect(rt);
        op, ok := decOpMap[reflect.Typeof(typ)];
        if !ok {
                // Special cases
                switch t := typ.(type) {
                case *reflect.SliceType:
+                       name = "element of " + name;
                        if _, ok := t.Elem().(*reflect.Uint8Type); ok {
                                op = decUint8Array;
                                break;
                        }
                        elemId := wireId.gobType().(*sliceType).Elem;
-                       elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
+                       elemOp, elemIndir, err := decOpFor(elemId, t.Elem(), name);
                        if err != nil {
                                return nil, 0, err
                        }
+                       ovfl := overflow(name);
                        op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
-                               state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir);
+                               state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl);
                        };
 
                case *reflect.ArrayType:
+                       name = "element of " + name;
                        elemId := wireId.gobType().(*arrayType).Elem;
-                       elemOp, elemIndir, err := decOpFor(elemId, t.Elem());
+                       elemOp, elemIndir, err := decOpFor(elemId, t.Elem(), name);
                        if err != nil {
                                return nil, 0, err
                        }
+                       ovfl := overflow(name);
                        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);
+                               state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl);
                        };
 
                case *reflect.StructType:
@@ -658,23 +664,25 @@ func compileDec(wireId typeId, rt reflect.Type) (engine *decEngine, err os.Error
                wireField := wireStruct.field[fieldnum];
                // Find the field of the local type with the same name.
                localField, present := srt.FieldByName(wireField.name);
+               ovfl := overflow(wireField.name);
                // TODO(r): anonymous names
                if !present || localField.Anonymous {
                        op, err := decIgnoreOpFor(wireField.id);
                        if err != nil {
                                return nil, err
                        }
-                       engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
+                       engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl};
                        continue;
                }
                if !compatibleType(localField.Type, wireField.id) {
-                       return nil, os.ErrorString("gob: wrong type for field " + wireField.name + " in type " + wireId.Name());
+                       details := " (" + wireField.id.String() + " incompatible with " + localField.Type.String() + ") in type " + wireId.Name();
+                       return nil, os.ErrorString("gob: wrong type for field " + wireField.name + details);
                }
-               op, indir, err := decOpFor(wireField.id, localField.Type);
+               op, indir, err := decOpFor(wireField.id, localField.Type, localField.Name);
                if err != nil {
                        return nil, err
                }
-               engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset)};
+               engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset), ovfl};
                engine.numInstr++;
        }
        return;
@@ -746,3 +754,44 @@ func decode(b *bytes.Buffer, wireId typeId, e interface{}) os.Error {
        }
        return decodeStruct(engine, rt.(*reflect.StructType), b, uintptr(v.Addr()), 0);
 }
+
+func init() {
+       // We assume that the size of float is sufficient to tell us whether it is
+       // equivalent to float32 or to float64.   This is very unlikely to be wrong.
+       var op decOp;
+       switch unsafe.Sizeof(float(0)) {
+       case unsafe.Sizeof(float32(0)):
+               op = decFloat32;
+       case unsafe.Sizeof(float64(0)):
+               op = decFloat64;
+       default:
+               panic("gob: unknown size of float", unsafe.Sizeof(float(0)));
+       }
+       decOpMap[valueKind(float(0))] = op;
+
+       // A similar assumption about int and uint.  Also assume int and uint have the same size.
+       var uop decOp;
+       switch unsafe.Sizeof(int(0)) {
+       case unsafe.Sizeof(int32(0)):
+               op = decInt32;
+               uop = decUint32;
+       case unsafe.Sizeof(int64(0)):
+               op = decInt64;
+               uop = decUint64;
+       default:
+               panic("gob: unknown size of int/uint", unsafe.Sizeof(int(0)));
+       }
+       decOpMap[valueKind(int(0))] = op;
+       decOpMap[valueKind(uint(0))] = uop;
+
+       // Finally uintptr
+       switch unsafe.Sizeof(uintptr(0)) {
+       case unsafe.Sizeof(uint32(0)):
+               uop = decUint32;
+       case unsafe.Sizeof(uint64(0)):
+               uop = decUint64;
+       default:
+               panic("gob: unknown size of uintptr", unsafe.Sizeof(uintptr(0)));
+       }
+       decOpMap[valueKind(uintptr(0))] = uop;
+}
index bfa2d69050d4ce68a786396aba97ac92a8d70dad..0589f38632a996640c18d7d6556501db35b1a375 100644 (file)
@@ -309,22 +309,22 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, length i
 }
 
 var encOpMap = map[reflect.Type] encOp {
-       reflect.Typeof((*reflect.BoolType)(nil)): encBool,
-       reflect.Typeof((*reflect.IntType)(nil)): encInt,
-       reflect.Typeof((*reflect.Int8Type)(nil)): encInt8,
-       reflect.Typeof((*reflect.Int16Type)(nil)): encInt16,
-       reflect.Typeof((*reflect.Int32Type)(nil)): encInt32,
-       reflect.Typeof((*reflect.Int64Type)(nil)): encInt64,
-       reflect.Typeof((*reflect.UintType)(nil)): encUint,
-       reflect.Typeof((*reflect.Uint8Type)(nil)): encUint8,
-       reflect.Typeof((*reflect.Uint16Type)(nil)): encUint16,
-       reflect.Typeof((*reflect.Uint32Type)(nil)): encUint32,
-       reflect.Typeof((*reflect.Uint64Type)(nil)): encUint64,
-       reflect.Typeof((*reflect.UintptrType)(nil)): encUintptr,
-       reflect.Typeof((*reflect.FloatType)(nil)): encFloat,
-       reflect.Typeof((*reflect.Float32Type)(nil)): encFloat32,
-       reflect.Typeof((*reflect.Float64Type)(nil)): encFloat64,
-       reflect.Typeof((*reflect.StringType)(nil)): encString,
+       valueKind(false): encBool,
+       valueKind(int(0)): encInt,
+       valueKind(int8(0)): encInt8,
+       valueKind(int16(0)): encInt16,
+       valueKind(int32(0)): encInt32,
+       valueKind(int64(0)): encInt64,
+       valueKind(uint(0)): encUint,
+       valueKind(uint8(0)): encUint8,
+       valueKind(uint16(0)): encUint16,
+       valueKind(uint32(0)): encUint32,
+       valueKind(uint64(0)): encUint64,
+       valueKind(uintptr(0)): encUintptr,
+       valueKind(float(0)): encFloat,
+       valueKind(float32(0)): encFloat32,
+       valueKind(float64(0)): encFloat64,
+       valueKind("x"): encString,
 }
 
 func getEncEngine(rt reflect.Type) *encEngine
index 1182a70c4313b3b3dfaf5f3020296efaa2047473..1a401eb1c52e59d1d9c1bb6090949f576361ad53 100644 (file)
@@ -66,7 +66,7 @@
        unsigned integers may be received into any unsigned integer variable; and floating
        point values may be received into any floating point variable.  However,
        the destination variable must be able to represent the value or the decode
-       operation will fail. (TODO(r): enforce this.)
+       operation will fail.
 
        Structs, arrays and slices are also supported.  Strings and arrays of bytes are
        supported with a special, efficient representation (see below).
index 68d047ffd3fc29e3f2ce81e2fe177c3856a4f0ba..f54746c323682ae81b1f85bdf4e1b1b125a4a572 100644 (file)
@@ -13,6 +13,30 @@ import (
        "unicode";
 )
 
+type kind reflect.Type
+
+// Reflection types are themselves interface values holding structs
+// describing the type.  Each type has a different struct so that struct can
+// be the kind.  For example, if typ is the reflect type for an int8, typ is
+// a pointer to a reflect.Int8Type struct; if typ is the reflect type for a
+// function, typ is a pointer to a reflect.FuncType struct; we use the type
+// of that pointer as the kind.
+
+// typeKind returns a reflect.Type representing typ's kind.  The kind is the
+// general kind of type:
+//     int8, int16, int, uint, float, func, chan, struct, and so on.
+// That is, all struct types have the same kind, all func types have the same
+// kind, all int8 types have the same kind, and so on.
+func typeKind(typ reflect.Type) kind {
+       return kind(reflect.Typeof(typ));
+}
+
+// valueKind returns the kind of the value type
+// stored inside the interface v.
+func valueKind(v interface{}) reflect.Type {
+       return typeKind(reflect.Typeof(v));
+}
+
 // A typeId represents a gob Type as an integer that can be passed on the wire.
 // Internally, typeIds are used as keys to a map to recover the underlying type info.
 type typeId int32