authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-16 02:55:08+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:11+03:00
log0782586b15302654501ebbcab3a2c63755a6fadb
treea4ad3079bb4aafe86a18aa72840e13bf3172df92
parent9f10dfcb546556b26b420633c7fa4d7de39f8fd7

Sema: divide by zero safety


4 files changed, 75 insertions(+), 8 deletions(-)

src/Sema.zig+43
......@@ -11877,6 +11877,45 @@ fn analyzeArithmetic(
1187711877 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
1187811878 }
1187911879 }
11880 switch (rs.air_tag) {
11881 .div_float, .div_exact, .div_trunc, .div_floor => {
11882 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
11883 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11884 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11885 const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type));
11886 break :ok try block.addInst(.{
11887 .tag = .reduce,
11888 .data = .{ .reduce = .{
11889 .operand = ok,
11890 .operation = .And,
11891 } },
11892 });
11893 } else ok: {
11894 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11895 break :ok try block.addBinOp(.cmp_neq, casted_rhs, zero);
11896 };
11897 try sema.addSafetyCheck(block, ok, .divide_by_zero);
11898 },
11899 .rem, .mod => {
11900 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
11901 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11902 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11903 const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type));
11904 break :ok try block.addInst(.{
11905 .tag = .reduce,
11906 .data = .{ .reduce = .{
11907 .operand = ok,
11908 .operation = .And,
11909 } },
11910 });
11911 } else ok: {
11912 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11913 break :ok try block.addBinOp(if (scalar_tag == .Int) .cmp_gt else .cmp_neq, casted_rhs, zero);
11914 };
11915 try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative);
11916 },
11917 else => {},
11918 }
1188011919 }
1188111920 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
1188211921}
......@@ -18813,6 +18852,8 @@ pub const PanicId = enum {
1881318852 integer_overflow,
1881418853 shl_overflow,
1881518854 shr_overflow,
18855 divide_by_zero,
18856 remainder_division_zero_negative,
1881618857};
1881718858
1881818859fn addSafetyCheck(
......@@ -19031,6 +19072,8 @@ fn safetyPanic(
1903119072 .integer_overflow => "integer overflow",
1903219073 .shl_overflow => "left shift overflowed bits",
1903319074 .shr_overflow => "right shift overflowed bits",
19075 .divide_by_zero => "division by zero",
19076 .remainder_division_zero_negative => "remainder division by zero or negative value",
1903419077 };
1903519078
1903619079 const msg_inst = msg_inst: {
test/cases/safety/integer division by zero - vectors.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
......@@ -16,5 +18,5 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
1618 return @divTrunc(a, b);
1719}
1820// run
19// backend=stage1
20// target=native
\ No newline at end of file
21// backend=llvm
22// target=native
test/cases/safety/integer division by zero.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810pub fn main() !void {
911 const x = div0(999, 0);
......@@ -14,5 +16,5 @@ fn div0(a: i32, b: i32) i32 {
1416 return @divTrunc(a, b);
1517}
1618// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/remainder division by negative number.zig created+20
......@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "remainder division by zero or negative value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = div0(999, -1);
12 _ = x;
13 return error.TestFailed;
14}
15fn div0(a: i32, b: i32) i32 {
16 return @rem(a, b);
17}
18// run
19// backend=llvm
20// target=native