Skip to content

Commit 0997758

Browse files
committed
fix: Prevent division by zero when folding constants
1 parent 760f4a1 commit 0997758

5 files changed

Lines changed: 59 additions & 12 deletions

File tree

src/Ast.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,17 @@ pub const Slice = struct {
683683
return Value.fromInteger(right_integer.? *% left_integer.?);
684684
},
685685
.Slash => {
686+
if (right_float == 0 or right_integer == 0) {
687+
reporter.reportErrorAt(
688+
.runtime,
689+
self.tokens.get(self.nodes.items(.location)[components.right]),
690+
self.tokens.get(self.nodes.items(.end_location)[components.right]),
691+
"Division by zero.",
692+
);
693+
694+
return error.DivisionByZero;
695+
}
696+
686697
if (right_float) |rf| {
687698
return Value.fromDouble(left_float.? / rf);
688699
}

src/Codegen.zig

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const Self = @This();
2323
pub const Error = error{
2424
CantCompile,
2525
UnwrappedNull,
26+
DivisionByZero,
2627
OutOfBound,
2728
ReachedMaximumMemoryUsage,
2829
WriteFailed,
@@ -439,14 +440,12 @@ fn generateNode(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj
439440
fn nodeValue(self: *Self, node: Ast.Node.Index) Error!?Value {
440441
const value = &self.ast.nodes.items(.value)[node];
441442

442-
if (value.* == null) {
443-
if (self.ast.isConstant(node)) {
444-
value.* = try self.ast.typeCheckAndToValue(
445-
node,
446-
&self.reporter,
447-
self.gc,
448-
);
449-
}
443+
if (value.* == null and self.ast.isConstant(node)) {
444+
value.* = try self.ast.typeCheckAndToValue(
445+
node,
446+
&self.reporter,
447+
self.gc,
448+
);
450449
}
451450

452451
return value.*;

src/Jit.zig

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub const Error = error{
1919
CantCompile,
2020
UnwrappedNull,
2121
OutOfBound,
22+
DivisionByZero,
2223
ReachedMaximumMemoryUsage,
2324
WriteFailed,
2425
} || std.mem.Allocator.Error || std.fmt.BufPrintError;
@@ -2731,7 +2732,7 @@ fn buildBinary(
27312732
},
27322733
else => unreachable,
27332734
}
2734-
},
2735+
},
27352736
.Star, .StarEqual => {
27362737
switch (def_type) {
27372738
.Integer => {
@@ -2746,12 +2747,44 @@ fn buildBinary(
27462747
}
27472748
},
27482749
.Slash, .SlashEqual => {
2750+
const zero_label = m.MIR_new_label(self.ctx);
2751+
27492752
switch (def_type) {
27502753
.Integer => {
2754+
self.BNE(
2755+
zero_label,
2756+
right,
2757+
m.MIR_new_uint_op(self.ctx, Value.fromInteger(0)),
2758+
);
2759+
2760+
// Exit if division by zero
2761+
// FIXME: would be great to be able to report cleanly the error but how to have string constant in MIR?
2762+
try self.buildExternApiCall(
2763+
.exit,
2764+
null,
2765+
&[_]m.MIR_op_t{m.MIR_new_uint_op(self.ctx, 1)},
2766+
);
2767+
2768+
self.append(zero_label);
27512769
self.DIV(dest, left, right);
27522770
try self.wrap(.Integer, dest, dest);
27532771
},
27542772
.Double => {
2773+
self.BNE(
2774+
zero_label,
2775+
right,
2776+
m.MIR_new_uint_op(self.ctx, Value.fromDouble(0)),
2777+
);
2778+
2779+
// Exit if division by zero
2780+
// FIXME: would be great to be able to report cleanly the error but how to have string constant in MIR?
2781+
try self.buildExternApiCall(
2782+
.exit,
2783+
null,
2784+
&[_]m.MIR_op_t{m.MIR_new_uint_op(self.ctx, 1)},
2785+
);
2786+
2787+
self.append(zero_label);
27552788
self.DDIV(left, left, right);
27562789
try self.wrap(.Double, left, dest);
27572790
},

src/Parser.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ pub const Error = error{
444444
ImportError,
445445
CantCompile,
446446
UnwrappedNull,
447+
DivisionByZero,
447448
OutOfBound,
448449
ReachedMaximumMemoryUsage,
449450
WriteFailed,
@@ -4887,7 +4888,7 @@ fn dot(self: *Self, can_assign: bool, callee: Ast.Node.Index) Error!Ast.Node.Ind
48874888
.{
48884889
.tag = .Dot,
48894890
.location = start_location,
4890-
.end_location = undefined,
4891+
.end_location = start_location,
48914892
.components = .{
48924893
.Dot = .{
48934894
.callee = callee,

src/vm.zig

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ pub const VM = struct {
428428
UnwrappedNull,
429429
OutOfBound,
430430
NumberOverflow,
431+
DivisionByZero,
431432
NotInFiber,
432433
FiberOver,
433434
BadNumber,
@@ -1532,7 +1533,9 @@ pub const VM = struct {
15321533
catch_value,
15331534
) catch |err| {
15341535
switch (err) {
1535-
Error.RuntimeError => return,
1536+
Error.RuntimeError,
1537+
Error.DivisionByZero,
1538+
=> return,
15361539
else => {
15371540
self.panic("Out of memory");
15381541
unreachable;
@@ -4800,7 +4803,7 @@ pub const VM = struct {
48004803
}
48014804
}
48024805

4803-
fn reportRuntimeErrorWithCurrentStack(self: *Self, message: []const u8) void {
4806+
pub fn reportRuntimeErrorWithCurrentStack(self: *Self, message: []const u8) void {
48044807
self.reportRuntimeError(
48054808
message,
48064809
if (self.currentFrame()) |frame|

0 commit comments

Comments
 (0)