diff --git a/builtins.go b/builtins.go index a4855fea..f64788fc 100644 --- a/builtins.go +++ b/builtins.go @@ -1194,6 +1194,16 @@ var builtinIsDecimal = liftNumericToBoolean(func(f float64) bool { return frac != 0 }) +// IEEE-754 double precision floats can safely store integers in the range [-2**53+1, 2**53-1]. +// We restrict bitwise operations to arguments in this range, since operating on larger values is +// likely to be a mistake. +// https://jsonnet.org/ref/language.html#number +// See also Javascript Number.{MIN_SAFE_INTEGER,MAX_SAFE_INTEGER} +const ( + maxSafeIntValue float64 = (1 << 53) - 1 + minSafeIntValue float64 = -maxSafeIntValue +) + func liftBitwise(f func(int64, int64) int64, positiveRightArg bool) func(*interpreter, value, value) (value, error) { return func(i *interpreter, xv, yv value) (value, error) { x, err := i.getNumber(xv) @@ -1204,12 +1214,12 @@ func liftBitwise(f func(int64, int64) int64, positiveRightArg bool) func(*interp if err != nil { return nil, err } - if x.value < math.MinInt64 || x.value > math.MaxInt64 { - msg := fmt.Sprintf("Bitwise operator argument %v outside of range [%v, %v]", x.value, int64(math.MinInt64), int64(math.MaxInt64)) + if x.value < minSafeIntValue || x.value > maxSafeIntValue { + msg := fmt.Sprintf("Bitwise operator argument %v outside of range [%v, %v]", x.value, int64(minSafeIntValue), int64(maxSafeIntValue)) return nil, makeRuntimeError(msg, i.getCurrentStackTrace()) } - if y.value < math.MinInt64 || y.value > math.MaxInt64 { - msg := fmt.Sprintf("Bitwise operator argument %v outside of range [%v, %v]", y.value, int64(math.MinInt64), int64(math.MaxInt64)) + if y.value < minSafeIntValue || y.value > maxSafeIntValue { + msg := fmt.Sprintf("Bitwise operator argument %v outside of range [%v, %v]", y.value, int64(minSafeIntValue), int64(maxSafeIntValue)) return nil, makeRuntimeError(msg, i.getCurrentStackTrace()) } if positiveRightArg && y.value < 0 { diff --git a/testdata/bitwise_and3.golden b/testdata/bitwise_and3.golden index c71c5212..62658937 100644 --- a/testdata/bitwise_and3.golden +++ b/testdata/bitwise_and3.golden @@ -1,4 +1,4 @@ -RUNTIME ERROR: Bitwise operator argument 1e+30 outside of range [-9223372036854775808, 9223372036854775807] +RUNTIME ERROR: Bitwise operator argument 1e+30 outside of range [-9007199254740991, 9007199254740991] ------------------------------------------------- testdata/bitwise_and3:1:1-10 $ diff --git a/testdata/bitwise_and7.golden b/testdata/bitwise_and7.golden index 788ba283..7a77fb36 100644 --- a/testdata/bitwise_and7.golden +++ b/testdata/bitwise_and7.golden @@ -1,4 +1,4 @@ -RUNTIME ERROR: Bitwise operator argument -1e+20 outside of range [-9223372036854775808, 9223372036854775807] +RUNTIME ERROR: Bitwise operator argument -1e+20 outside of range [-9007199254740991, 9007199254740991] ------------------------------------------------- testdata/bitwise_and7:1:1-11 $ diff --git a/testdata/bitwise_or9.golden b/testdata/bitwise_or9.golden index aef5454e..3bcdce0e 100644 --- a/testdata/bitwise_or9.golden +++ b/testdata/bitwise_or9.golden @@ -1 +1,10 @@ -4611686018427387904 +RUNTIME ERROR: Bitwise operator argument 4.611686018427388e+18 outside of range [-9007199254740991, 9007199254740991] +------------------------------------------------- + testdata/bitwise_or9:1:1-14 $ + +(1 << 62) | 1 + +------------------------------------------------- + During evaluation + +