Commit 483e4fc4 authored by Rob Pike's avatar Rob Pike

- clean up code creating keys for type maps

- 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
parent 08b5b484
...@@ -7,6 +7,7 @@ package gob ...@@ -7,6 +7,7 @@ package gob
import ( import (
"bytes"; "bytes";
"gob"; "gob";
"math";
"os"; "os";
"reflect"; "reflect";
"strings"; "strings";
...@@ -347,21 +348,22 @@ func newdecodeState(data []byte) *decodeState { ...@@ -347,21 +348,22 @@ func newdecodeState(data []byte) *decodeState {
// Test instruction execution for decoding. // Test instruction execution for decoding.
// Do not run the machine yet; instead do individual instructions crafted by hand. // Do not run the machine yet; instead do individual instructions crafted by hand.
func TestScalarDecInstructions(t *testing.T) { func TestScalarDecInstructions(t *testing.T) {
ovfl := os.ErrorString("overflow");
// bool // bool
{ {
var data struct { a bool }; var data struct { a bool };
instr := &decInstr{ decBool, 6, 0, 0 }; instr := &decInstr{ decBool, 6, 0, 0, ovfl };
state := newdecodeState(boolResult); state := newdecodeState(boolResult);
execDec("bool", instr, state, t, unsafe.Pointer(&data)); execDec("bool", instr, state, t, unsafe.Pointer(&data));
if data.a != true { if data.a != true {
t.Errorf("int a = %v not true", data.a) t.Errorf("bool a = %v not true", data.a)
} }
} }
// int // int
{ {
var data struct { 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); state := newdecodeState(signedResult);
execDec("int", instr, state, t, unsafe.Pointer(&data)); execDec("int", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
...@@ -372,139 +374,150 @@ func TestScalarDecInstructions(t *testing.T) { ...@@ -372,139 +374,150 @@ func TestScalarDecInstructions(t *testing.T) {
// uint // uint
{ {
var data struct { a 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); state := newdecodeState(unsignedResult);
execDec("uint", instr, state, t, unsafe.Pointer(&data)); execDec("uint", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("uint a = %v not 17", data.a)
} }
} }
// int8 // int8
{ {
var data struct { a int8 }; var data struct { a int8 };
instr := &decInstr{ decInt8, 6, 0, 0 }; instr := &decInstr{ decInt8, 6, 0, 0, ovfl };
state := newdecodeState(signedResult); state := newdecodeState(signedResult);
execDec("int8", instr, state, t, unsafe.Pointer(&data)); execDec("int8", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("int8 a = %v not 17", data.a)
} }
} }
// uint8 // uint8
{ {
var data struct { a uint8 }; var data struct { a uint8 };
instr := &decInstr{ decUint8, 6, 0, 0 }; instr := &decInstr{ decUint8, 6, 0, 0, ovfl };
state := newdecodeState(unsignedResult); state := newdecodeState(unsignedResult);
execDec("uint8", instr, state, t, unsafe.Pointer(&data)); execDec("uint8", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("uint8 a = %v not 17", data.a)
} }
} }
// int16 // int16
{ {
var data struct { a int16 }; var data struct { a int16 };
instr := &decInstr{ decInt16, 6, 0, 0 }; instr := &decInstr{ decInt16, 6, 0, 0, ovfl };
state := newdecodeState(signedResult); state := newdecodeState(signedResult);
execDec("int16", instr, state, t, unsafe.Pointer(&data)); execDec("int16", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("int16 a = %v not 17", data.a)
} }
} }
// uint16 // uint16
{ {
var data struct { a uint16 }; var data struct { a uint16 };
instr := &decInstr{ decUint16, 6, 0, 0 }; instr := &decInstr{ decUint16, 6, 0, 0, ovfl };
state := newdecodeState(unsignedResult); state := newdecodeState(unsignedResult);
execDec("uint16", instr, state, t, unsafe.Pointer(&data)); execDec("uint16", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("uint16 a = %v not 17", data.a)
} }
} }
// int32 // int32
{ {
var data struct { a int32 }; var data struct { a int32 };
instr := &decInstr{ decInt32, 6, 0, 0 }; instr := &decInstr{ decInt32, 6, 0, 0, ovfl };
state := newdecodeState(signedResult); state := newdecodeState(signedResult);
execDec("int32", instr, state, t, unsafe.Pointer(&data)); execDec("int32", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("int32 a = %v not 17", data.a)
} }
} }
// uint32 // uint32
{ {
var data struct { a uint32 }; var data struct { a uint32 };
instr := &decInstr{ decUint32, 6, 0, 0 }; instr := &decInstr{ decUint32, 6, 0, 0, ovfl };
state := newdecodeState(unsignedResult); state := newdecodeState(unsignedResult);
execDec("uint32", instr, state, t, unsafe.Pointer(&data)); execDec("uint32", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { 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 // int64
{ {
var data struct { a int64 }; var data struct { a int64 };
instr := &decInstr{ decInt64, 6, 0, 0 }; instr := &decInstr{ decInt64, 6, 0, 0, ovfl };
state := newdecodeState(signedResult); state := newdecodeState(signedResult);
execDec("int64", instr, state, t, unsafe.Pointer(&data)); execDec("int64", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("int64 a = %v not 17", data.a)
} }
} }
// uint64 // uint64
{ {
var data struct { a uint64 }; var data struct { a uint64 };
instr := &decInstr{ decUint64, 6, 0, 0 }; instr := &decInstr{ decUint64, 6, 0, 0, ovfl };
state := newdecodeState(unsignedResult); state := newdecodeState(unsignedResult);
execDec("uint64", instr, state, t, unsafe.Pointer(&data)); execDec("uint64", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("uint64 a = %v not 17", data.a)
} }
} }
// float // float
{ {
var data struct { 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); state := newdecodeState(floatResult);
execDec("float", instr, state, t, unsafe.Pointer(&data)); execDec("float", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("float a = %v not 17", data.a)
} }
} }
// float32 // float32
{ {
var data struct { a float32 }; var data struct { a float32 };
instr := &decInstr{ decFloat32, 6, 0, 0 }; instr := &decInstr{ decFloat32, 6, 0, 0, ovfl };
state := newdecodeState(floatResult); state := newdecodeState(floatResult);
execDec("float32", instr, state, t, unsafe.Pointer(&data)); execDec("float32", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("float32 a = %v not 17", data.a)
} }
} }
// float64 // float64
{ {
var data struct { a float64 }; var data struct { a float64 };
instr := &decInstr{ decFloat64, 6, 0, 0 }; instr := &decInstr{ decFloat64, 6, 0, 0, ovfl };
state := newdecodeState(floatResult); state := newdecodeState(floatResult);
execDec("float64", instr, state, t, unsafe.Pointer(&data)); execDec("float64", instr, state, t, unsafe.Pointer(&data));
if data.a != 17 { if data.a != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("float64 a = %v not 17", data.a)
} }
} }
// bytes == []uint8 // bytes == []uint8
{ {
var data struct { a []byte }; var data struct { a []byte };
instr := &decInstr{ decUint8Array, 6, 0, 0 }; instr := &decInstr{ decUint8Array, 6, 0, 0, ovfl };
state := newdecodeState(bytesResult); state := newdecodeState(bytesResult);
execDec("bytes", instr, state, t, unsafe.Pointer(&data)); execDec("bytes", instr, state, t, unsafe.Pointer(&data));
if string(data.a) != "hello" { if string(data.a) != "hello" {
...@@ -515,7 +528,7 @@ func TestScalarDecInstructions(t *testing.T) { ...@@ -515,7 +528,7 @@ func TestScalarDecInstructions(t *testing.T) {
// string // string
{ {
var data struct { a string }; var data struct { a string };
instr := &decInstr{ decString, 6, 0, 0 }; instr := &decInstr{ decString, 6, 0, 0, ovfl };
state := newdecodeState(bytesResult); state := newdecodeState(bytesResult);
execDec("bytes", instr, state, t, unsafe.Pointer(&data)); execDec("bytes", instr, state, t, unsafe.Pointer(&data));
if data.a != "hello" { if data.a != "hello" {
...@@ -559,6 +572,157 @@ func TestEndToEnd(t *testing.T) { ...@@ -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) { func TestNesting(t *testing.T) {
type RT struct { type RT struct {
a string; a string;
......
This diff is collapsed.
...@@ -309,22 +309,22 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, length i ...@@ -309,22 +309,22 @@ func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, length i
} }
var encOpMap = map[reflect.Type] encOp { var encOpMap = map[reflect.Type] encOp {
reflect.Typeof((*reflect.BoolType)(nil)): encBool, valueKind(false): encBool,
reflect.Typeof((*reflect.IntType)(nil)): encInt, valueKind(int(0)): encInt,
reflect.Typeof((*reflect.Int8Type)(nil)): encInt8, valueKind(int8(0)): encInt8,
reflect.Typeof((*reflect.Int16Type)(nil)): encInt16, valueKind(int16(0)): encInt16,
reflect.Typeof((*reflect.Int32Type)(nil)): encInt32, valueKind(int32(0)): encInt32,
reflect.Typeof((*reflect.Int64Type)(nil)): encInt64, valueKind(int64(0)): encInt64,
reflect.Typeof((*reflect.UintType)(nil)): encUint, valueKind(uint(0)): encUint,
reflect.Typeof((*reflect.Uint8Type)(nil)): encUint8, valueKind(uint8(0)): encUint8,
reflect.Typeof((*reflect.Uint16Type)(nil)): encUint16, valueKind(uint16(0)): encUint16,
reflect.Typeof((*reflect.Uint32Type)(nil)): encUint32, valueKind(uint32(0)): encUint32,
reflect.Typeof((*reflect.Uint64Type)(nil)): encUint64, valueKind(uint64(0)): encUint64,
reflect.Typeof((*reflect.UintptrType)(nil)): encUintptr, valueKind(uintptr(0)): encUintptr,
reflect.Typeof((*reflect.FloatType)(nil)): encFloat, valueKind(float(0)): encFloat,
reflect.Typeof((*reflect.Float32Type)(nil)): encFloat32, valueKind(float32(0)): encFloat32,
reflect.Typeof((*reflect.Float64Type)(nil)): encFloat64, valueKind(float64(0)): encFloat64,
reflect.Typeof((*reflect.StringType)(nil)): encString, valueKind("x"): encString,
} }
func getEncEngine(rt reflect.Type) *encEngine func getEncEngine(rt reflect.Type) *encEngine
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
unsigned integers may be received into any unsigned integer variable; and floating unsigned integers may be received into any unsigned integer variable; and floating
point values may be received into any floating point variable. However, point values may be received into any floating point variable. However,
the destination variable must be able to represent the value or the decode 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 Structs, arrays and slices are also supported. Strings and arrays of bytes are
supported with a special, efficient representation (see below). supported with a special, efficient representation (see below).
......
...@@ -13,6 +13,30 @@ import ( ...@@ -13,6 +13,30 @@ import (
"unicode"; "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. // 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. // Internally, typeIds are used as keys to a map to recover the underlying type info.
type typeId int32 type typeId int32
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment