Handle overflows
This commit is contained in:
@@ -1047,15 +1047,15 @@ func TestUnmarshalOverflow(t *testing.T) {
|
|||||||
testCases := []TestCase{
|
testCases := []TestCase{
|
||||||
{
|
{
|
||||||
desc: "byte",
|
desc: "byte",
|
||||||
input: `u8 = 300`,
|
input: `U8 = 300`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "int8",
|
desc: "int8",
|
||||||
input: `i8 = 300`,
|
input: `I8 = 300`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "float32",
|
desc: "float32",
|
||||||
input: `f32 = 1e300`,
|
input: `F32 = 1e300`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package reflectbuild
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -495,33 +496,172 @@ func convert(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
|||||||
return result.Elem(), nil
|
return result.Elem(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IntegerOverflowErr struct {
|
||||||
|
value int64
|
||||||
|
min int64
|
||||||
|
max int64
|
||||||
|
kind reflect.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e IntegerOverflowErr) Error() string {
|
||||||
|
return fmt.Sprintf("integer overflow: cannot store %d in %s [%d, %d]", e.value, e.kind, e.min, e.max)
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxInt = int64(^uint(0) >> 1)
|
||||||
|
const minInt = -maxInt - 1
|
||||||
|
|
||||||
func convertInt(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
func convertInt(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
return value.Convert(t), nil // reflect.TypeOf(int64(0))
|
x := value.Int()
|
||||||
|
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Int:
|
||||||
|
if x > maxInt || x < minInt {
|
||||||
|
return value, IntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
min: minInt,
|
||||||
|
max: maxInt,
|
||||||
|
kind: t.Kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int8:
|
||||||
|
if x > math.MaxInt8 || x < math.MinInt8 {
|
||||||
|
return value, IntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
min: math.MinInt8,
|
||||||
|
max: math.MaxInt8,
|
||||||
|
kind: t.Kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
if x > math.MaxInt16 || x < math.MinInt16 {
|
||||||
|
return value, IntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
min: math.MinInt16,
|
||||||
|
max: math.MaxInt16,
|
||||||
|
kind: t.Kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if x > math.MaxInt32 || x < math.MinInt32 {
|
||||||
|
return value, IntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
min: math.MinInt32,
|
||||||
|
max: math.MaxInt32,
|
||||||
|
kind: t.Kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Int64:
|
||||||
|
if x > math.MaxInt64 || x < math.MinInt64 {
|
||||||
|
return value, IntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
min: math.MinInt64,
|
||||||
|
max: math.MaxInt64,
|
||||||
|
kind: t.Kind(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.Convert(t), nil
|
||||||
default:
|
default:
|
||||||
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnsignedIntegerOverflowErr struct {
|
||||||
|
value uint64
|
||||||
|
max uint64
|
||||||
|
kind reflect.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnsignedIntegerOverflowErr) Error() string {
|
||||||
|
return fmt.Sprintf("unsigned integer overflow: cannot store %d in %s [max %d]", e.value, e.kind, e.max)
|
||||||
|
}
|
||||||
|
|
||||||
func convertUint(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
func convertUint(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
err := convertUintOverflowCheck(t.Kind(), value.Uint())
|
||||||
|
if err != nil {
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
return value.Convert(t), nil // reflect.TypeOf(int64(0))
|
return value.Convert(t), nil // reflect.TypeOf(int64(0))
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
x := value.Int()
|
signed := value.Int()
|
||||||
if x < 0 {
|
if signed < 0 {
|
||||||
return value, fmt.Errorf("cannot store negative integer '%d' into %s", x, t.Kind())
|
return value, fmt.Errorf("cannot store negative integer '%d' into %s", signed, t.Kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x := uint64(signed)
|
||||||
|
err := convertUintOverflowCheck(t.Kind(), x)
|
||||||
|
if err != nil {
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
|
||||||
return value.Convert(t), nil
|
return value.Convert(t), nil
|
||||||
default:
|
default:
|
||||||
return value, fmt.Errorf("cannot convert %s to unsigned integer (%s)", value.Kind(), t.Kind())
|
return value, fmt.Errorf("cannot convert %s to unsigned integer (%s)", value.Kind(), t.Kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxUint = uint64(^uint(0))
|
||||||
|
|
||||||
|
func convertUintOverflowCheck(t reflect.Kind, x uint64) error {
|
||||||
|
switch t {
|
||||||
|
case reflect.Uint:
|
||||||
|
if x > maxUint {
|
||||||
|
return UnsignedIntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
max: maxUint,
|
||||||
|
kind: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint8:
|
||||||
|
if x > math.MaxUint8 {
|
||||||
|
return UnsignedIntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
max: math.MaxUint8,
|
||||||
|
kind: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
if x > math.MaxUint16 {
|
||||||
|
return UnsignedIntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
max: math.MaxUint16,
|
||||||
|
kind: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
if x > math.MaxUint32 {
|
||||||
|
return UnsignedIntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
max: math.MaxUint32,
|
||||||
|
kind: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint64:
|
||||||
|
if x > math.MaxUint64 {
|
||||||
|
return UnsignedIntegerOverflowErr{
|
||||||
|
value: x,
|
||||||
|
max: math.MaxUint64,
|
||||||
|
kind: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func convertFloat(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
func convertFloat(t reflect.Type, value reflect.Value) (reflect.Value, error) {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
|
if t.Kind() == reflect.Float32 {
|
||||||
|
f := value.Float()
|
||||||
|
if f > math.MaxFloat32 {
|
||||||
|
return value, fmt.Errorf("float overflow: %f does not fit in %s [max %f]")
|
||||||
|
}
|
||||||
|
}
|
||||||
return value.Convert(t), nil
|
return value.Convert(t), nil
|
||||||
default:
|
default:
|
||||||
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
return value, fmt.Errorf("cannot convert %s to integer (%s)", value.Kind(), t.Kind())
|
||||||
|
|||||||
Reference in New Issue
Block a user