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;
......
...@@ -29,6 +29,10 @@ type decodeState struct { ...@@ -29,6 +29,10 @@ type decodeState struct {
fieldnum int; // the last field number read. 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. // decodeUintReader reads an encoded unsigned integer from an io.Reader.
// Used only by the Decoder to read the message length. // Used only by the Decoder to read the message length.
func decodeUintReader(r io.Reader, oneByte []byte) (x uint64, err os.Error) { 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) { ...@@ -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. // decodeUint reads an encoded unsigned integer from state.r.
// Sets state.err. If state.err is already non-nil, it does nothing. // Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
func decodeUint(state *decodeState) (x uint64) { func decodeUint(state *decodeState) (x uint64) {
if state.err != nil { if state.err != nil {
return return
...@@ -71,6 +76,7 @@ func decodeUint(state *decodeState) (x uint64) { ...@@ -71,6 +76,7 @@ func decodeUint(state *decodeState) (x uint64) {
// decodeInt reads an encoded signed integer from state.r. // decodeInt reads an encoded signed integer from state.r.
// Sets state.err. If state.err is already non-nil, it does nothing. // Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
func decodeInt(state *decodeState) int64 { func decodeInt(state *decodeState) int64 {
x := decodeUint(state); x := decodeUint(state);
if state.err != nil { if state.err != nil {
...@@ -91,6 +97,7 @@ type decInstr struct { ...@@ -91,6 +97,7 @@ type decInstr struct {
field int; // field number of the wire type field int; // field number of the wire type
indir int; // how many pointer indirections to reach the value in the struct indir int; // how many pointer indirections to reach the value in the struct
offset uintptr; // offset in the structure of the field to encode 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 // 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) { ...@@ -126,26 +133,6 @@ func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
*(*bool)(p) = decodeInt(state) != 0; *(*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) { func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
if i.indir > 0 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if *(*unsafe.Pointer)(p) == nil {
...@@ -153,7 +140,12 @@ func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) { ...@@ -153,7 +140,12 @@ func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
} }
p = *(*unsafe.Pointer)(p); 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) { func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -163,7 +155,12 @@ 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); 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) { func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -173,7 +170,12 @@ 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); 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) { func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -183,7 +185,12 @@ 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); 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) { func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -193,7 +200,12 @@ 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); 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) { func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -203,7 +215,12 @@ 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); 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) { func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -226,16 +243,6 @@ func decUint64(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)); *(*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 // Floating-point numbers are transmitted as uint64s holding the bits
// of the underlying representation. They are sent byte-reversed, with // of the underlying representation. They are sent byte-reversed, with
// the exponent end coming out first, so integer floating point numbers // the exponent end coming out first, so integer floating point numbers
...@@ -251,16 +258,6 @@ func floatFromBits(u uint64) float64 { ...@@ -251,16 +258,6 @@ func floatFromBits(u uint64) float64 {
return math.Float64frombits(v); 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) { func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
if i.indir > 0 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if *(*unsafe.Pointer)(p) == nil {
...@@ -268,7 +265,16 @@ func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) { ...@@ -268,7 +265,16 @@ func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
} }
p = *(*unsafe.Pointer)(p); 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) { func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
...@@ -386,8 +392,8 @@ func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error { ...@@ -386,8 +392,8 @@ func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
return state.err return state.err
} }
func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int) os.Error { func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) os.Error {
instr := &decInstr{elemOp, 0, elemIndir, 0}; instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl};
for i := 0; i < length && state.err == nil; i++ { for i := 0; i < length && state.err == nil; i++ {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
if elemIndir > 1 { if elemIndir > 1 {
...@@ -399,7 +405,7 @@ func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uint ...@@ -399,7 +405,7 @@ func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uint
return state.err 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 { if indir > 0 {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
if *(*unsafe.Pointer)(up) == nil { if *(*unsafe.Pointer)(up) == nil {
...@@ -413,11 +419,11 @@ func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp ...@@ -413,11 +419,11 @@ func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp
if n := decodeUint(state); n != uint64(length) { if n := decodeUint(state); n != uint64(length) {
return os.ErrorString("gob: length mismatch in decodeArray"); 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 { 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++ { for i := 0; i < length && state.err == nil; i++ {
elemOp(instr, state, nil); elemOp(instr, state, nil);
} }
...@@ -431,7 +437,7 @@ func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error { ...@@ -431,7 +437,7 @@ func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error {
return ignoreArrayHelper(state, elemOp, length); 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)); length := uintptr(decodeUint(state));
if indir > 0 { if indir > 0 {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
...@@ -448,7 +454,7 @@ func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp ...@@ -448,7 +454,7 @@ func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp
hdrp.Data = uintptr(unsafe.Pointer(&data[0])); hdrp.Data = uintptr(unsafe.Pointer(&data[0]));
hdrp.Len = int(length); hdrp.Len = int(length);
hdrp.Cap = 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 { func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
...@@ -456,22 +462,18 @@ 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 { var decOpMap = map[reflect.Type] decOp {
reflect.Typeof((*reflect.BoolType)(nil)): decBool, valueKind(false): decBool,
reflect.Typeof((*reflect.IntType)(nil)): decInt, valueKind(int8(0)): decInt8,
reflect.Typeof((*reflect.Int8Type)(nil)): decInt8, valueKind(int16(0)): decInt16,
reflect.Typeof((*reflect.Int16Type)(nil)): decInt16, valueKind(int32(0)): decInt32,
reflect.Typeof((*reflect.Int32Type)(nil)): decInt32, valueKind(int64(0)): decInt64,
reflect.Typeof((*reflect.Int64Type)(nil)): decInt64, valueKind(uint8(0)): decUint8,
reflect.Typeof((*reflect.UintType)(nil)): decUint, valueKind(uint16(0)): decUint16,
reflect.Typeof((*reflect.Uint8Type)(nil)): decUint8, valueKind(uint32(0)): decUint32,
reflect.Typeof((*reflect.Uint16Type)(nil)): decUint16, valueKind(uint64(0)): decUint64,
reflect.Typeof((*reflect.Uint32Type)(nil)): decUint32, valueKind(float32(0)): decFloat32,
reflect.Typeof((*reflect.Uint64Type)(nil)): decUint64, valueKind(float64(0)): decFloat64,
reflect.Typeof((*reflect.UintptrType)(nil)): decUintptr, valueKind("x"): decString,
reflect.Typeof((*reflect.FloatType)(nil)): decFloat,
reflect.Typeof((*reflect.Float32Type)(nil)): decFloat32,
reflect.Typeof((*reflect.Float64Type)(nil)): decFloat64,
reflect.Typeof((*reflect.StringType)(nil)): decString,
} }
var decIgnoreOpMap = map[typeId] decOp { var decIgnoreOpMap = map[typeId] decOp {
...@@ -488,34 +490,38 @@ func getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) ...@@ -488,34 +490,38 @@ func getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error)
// Return the decoding op for the base type under rt and // Return the decoding op for the base type under rt and
// the indirection count to reach it. // 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); typ, indir := indirect(rt);
op, ok := decOpMap[reflect.Typeof(typ)]; op, ok := decOpMap[reflect.Typeof(typ)];
if !ok { if !ok {
// Special cases // Special cases
switch t := typ.(type) { switch t := typ.(type) {
case *reflect.SliceType: case *reflect.SliceType:
name = "element of " + name;
if _, ok := t.Elem().(*reflect.Uint8Type); ok { if _, ok := t.Elem().(*reflect.Uint8Type); ok {
op = decUint8Array; op = decUint8Array;
break; break;
} }
elemId := wireId.gobType().(*sliceType).Elem; elemId := wireId.gobType().(*sliceType).Elem;
elemOp, elemIndir, err := decOpFor(elemId, t.Elem()); elemOp, elemIndir, err := decOpFor(elemId, t.Elem(), name);
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
ovfl := overflow(name);
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) { 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: case *reflect.ArrayType:
name = "element of " + name;
elemId := wireId.gobType().(*arrayType).Elem; elemId := wireId.gobType().(*arrayType).Elem;
elemOp, elemIndir, err := decOpFor(elemId, t.Elem()); elemOp, elemIndir, err := decOpFor(elemId, t.Elem(), name);
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
ovfl := overflow(name);
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) { 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: case *reflect.StructType:
...@@ -658,23 +664,25 @@ func compileDec(wireId typeId, rt reflect.Type) (engine *decEngine, err os.Error ...@@ -658,23 +664,25 @@ func compileDec(wireId typeId, rt reflect.Type) (engine *decEngine, err os.Error
wireField := wireStruct.field[fieldnum]; wireField := wireStruct.field[fieldnum];
// Find the field of the local type with the same name. // Find the field of the local type with the same name.
localField, present := srt.FieldByName(wireField.name); localField, present := srt.FieldByName(wireField.name);
ovfl := overflow(wireField.name);
// TODO(r): anonymous names // TODO(r): anonymous names
if !present || localField.Anonymous { if !present || localField.Anonymous {
op, err := decIgnoreOpFor(wireField.id); op, err := decIgnoreOpFor(wireField.id);
if err != nil { if err != nil {
return nil, err return nil, err
} }
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0}; engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl};
continue; continue;
} }
if !compatibleType(localField.Type, wireField.id) { 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 { if err != nil {
return nil, err 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++; engine.numInstr++;
} }
return; return;
...@@ -746,3 +754,44 @@ func decode(b *bytes.Buffer, wireId typeId, e interface{}) os.Error { ...@@ -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); 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;
}
...@@ -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