ReviewOS

also looking at this

home-lang/home

fix(interpreter): report overflow when dividing the minimum integer by -1

#931
Open mkantautas wants to merge fix/interpreter-div-overflow into main
2 files +36 -4
packages/interpreter/src/interpreter.zigmodified+7-4
Changes to packages/interpreter/src/interpreter.zig
@@ -11615,8 +11615,8 @@ pub const Interpreter = struct {
1161511615 const result: i64 = switch (op) {
1161611616 .Sub => std.math.sub(i64, l, r) catch return error.RuntimeError,
1161711617 .Mul => std.math.mul(i64, l, r) catch return error.RuntimeError,
11618 .Div => @divTrunc(l, r),
11619 .IntDiv => @divTrunc(l, r),
11618 .Div => std.math.divTrunc(i64, l, r) catch return error.RuntimeError,
11619 .IntDiv => std.math.divTrunc(i64, l, r) catch return error.RuntimeError,
1162011620 // Use truncated remainder (@rem) for consistency with TypeScript/C/Java
1162111621 // semantics where the sign of the result matches the dividend:
1162211622 // -7 % 3 == -1 (not 2 as with floored @mod)
@@ -11766,7 +11766,7 @@ pub const Interpreter = struct {
1176611766 .SaturatingAdd => std.math.add(i64, l, r) catch null,
1176711767 .SaturatingSub => std.math.sub(i64, l, r) catch null,
1176811768 .SaturatingMul => std.math.mul(i64, l, r) catch null,
11769 .SaturatingDiv => if (r == 0) null else @divTrunc(l, r),
11769 .SaturatingDiv => if (r == 0) null else std.math.divTrunc(i64, l, r) catch null,
1177011770 else => null,
1177111771 };
1177211772
@@ -11836,7 +11836,10 @@ pub const Interpreter = struct {
1183611836 .CheckedDiv => if (r == 0) {
1183711837 std.debug.print("Division by zero in checked division\n", .{});
1183811838 return error.RuntimeError;
11839 } else @divTrunc(l, r),
11839 } else std.math.divTrunc(i64, l, r) catch {
11840 std.debug.print("Integer overflow in checked division\n", .{});
11841 return error.RuntimeError;
11842 },
1184011843 else => l,
1184111844 };
1184211845
packages/interpreter/tests/program_eval_test.zigmodified+29-0
Changes to packages/interpreter/tests/program_eval_test.zig
@@ -59,6 +59,35 @@ test "eval: nested arithmetic expression" {
5959 try runProgram("fn main() { print((1 + 2) * 3 - 4) }");
6060}
6161
62test "eval: dividing the minimum integer by -1 reports the overflow" {
63 try testing.expectError(error.RuntimeError, runProgram(
64 \\fn main() {
65 \\ let x = -9223372036854775807 - 1
66 \\ print(x / -1)
67 \\}
68 ));
69 try testing.expectError(error.RuntimeError, runProgram(
70 \\fn main() {
71 \\ let x = -9223372036854775807 - 1
72 \\ print(x ~/ -1)
73 \\}
74 ));
75 try testing.expectError(error.RuntimeError, runProgram(
76 \\fn main() {
77 \\ let x = -9223372036854775807 - 1
78 \\ print(x /! -1)
79 \\}
80 ));
81 try runProgram(
82 \\fn main() {
83 \\ let x = -9223372036854775807 - 1
84 \\ assert(is_none(x /? -1))
85 \\ assert(x / 1 == x)
86 \\ assert(x ~/ 2 == -4611686018427387904)
87 \\}
88 );
89}
90
6291test "eval: multiple statements and a returning function" {
6392 // Exercises several evaluateExpression entries across statements and a
6493 // user-function call — all of which were unreachable while expression depth