authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-16 15:56:16+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:11+03:00
log76d099950aa2e5fee4897c8bc401946f39ed87a4
treece8b2a2ed2673777f2f4a0aa73351c47491bfd0c
parent0782586b15302654501ebbcab3a2c63755a6fadb

Sema: cast negative to unsigned safety


4 files changed, 18 insertions(+), 12 deletions(-)

src/Sema.zig+5-2
...@@ -8092,6 +8092,7 @@ fn intCast(...@@ -8092,6 +8092,7 @@ fn intCast(
8092 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);8092 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
8093 break :ok is_in_range;8093 break :ok is_in_range;
8094 };8094 };
8095 // TODO negative_to_unsigned?
8095 try sema.addSafetyCheck(block, ok, .cast_truncated_data);8096 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
8096 } else {8097 } else {
8097 const ok = if (is_vector) ok: {8098 const ok = if (is_vector) ok: {
...@@ -8116,7 +8117,7 @@ fn intCast(...@@ -8116,7 +8117,7 @@ fn intCast(
8116 const ok = if (is_vector) ok: {8117 const ok = if (is_vector) ok: {
8117 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);8118 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
8118 const zero_inst = try sema.addConstant(operand_ty, zero_val);8119 const zero_inst = try sema.addConstant(operand_ty, zero_val);
8119 const is_in_range = try block.addCmpVector(operand, zero_inst, .lte, try sema.addType(operand_ty));8120 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty));
8120 const all_in_range = try block.addInst(.{8121 const all_in_range = try block.addInst(.{
8121 .tag = .reduce,8122 .tag = .reduce,
8122 .data = .{ .reduce = .{8123 .data = .{ .reduce = .{
...@@ -8130,7 +8131,7 @@ fn intCast(...@@ -8130,7 +8131,7 @@ fn intCast(
8130 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);8131 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
8131 break :ok is_in_range;8132 break :ok is_in_range;
8132 };8133 };
8133 try sema.addSafetyCheck(block, ok, .cast_truncated_data);8134 try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
8134 }8135 }
8135 }8136 }
8136 return block.addTyOp(.intcast, dest_ty, operand);8137 return block.addTyOp(.intcast, dest_ty, operand);
...@@ -18849,6 +18850,7 @@ pub const PanicId = enum {...@@ -18849,6 +18850,7 @@ pub const PanicId = enum {
18849 incorrect_alignment,18850 incorrect_alignment,
18850 invalid_error_code,18851 invalid_error_code,
18851 cast_truncated_data,18852 cast_truncated_data,
18853 negative_to_unsigned,
18852 integer_overflow,18854 integer_overflow,
18853 shl_overflow,18855 shl_overflow,
18854 shr_overflow,18856 shr_overflow,
...@@ -19069,6 +19071,7 @@ fn safetyPanic(...@@ -19069,6 +19071,7 @@ fn safetyPanic(
19069 .incorrect_alignment => "incorrect alignment",19071 .incorrect_alignment => "incorrect alignment",
19070 .invalid_error_code => "invalid error code",19072 .invalid_error_code => "invalid error code",
19071 .cast_truncated_data => "integer cast truncated bits",19073 .cast_truncated_data => "integer cast truncated bits",
19074 .negative_to_unsigned => "attempt to cast negative value to unsigned integer",
19072 .integer_overflow => "integer overflow",19075 .integer_overflow => "integer overflow",
19073 .shl_overflow => "left shift overflowed bits",19076 .shl_overflow => "left shift overflowed bits",
19074 .shr_overflow => "right shift overflowed bits",19077 .shr_overflow => "right shift overflowed bits",
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 var value: c_short = -1;11 var value: c_short = -1;
...@@ -12,5 +14,5 @@ pub fn main() !void {...@@ -12,5 +14,5 @@ pub fn main() !void {
12 return error.TestFailed;14 return error.TestFailed;
13}15}
14// run16// run
15// backend=stage1
16// target=native
\ No newline at end of file
17// backend=llvm
18// target=native
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +6-5
...@@ -1,11 +1,12 @@...@@ -1,11 +1,12 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8
9pub fn main() !void {10pub fn main() !void {
10 const x = unsigned_cast(-10);11 const x = unsigned_cast(-10);
11 if (x == 0) return error.Whatever;12 if (x == 0) return error.Whatever;
...@@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 {...@@ -15,5 +16,5 @@ fn unsigned_cast(x: i32) u32 {
15 return @intCast(u32, x);16 return @intCast(u32, x);
16}17}
17// run18// run
18// backend=stage1
19// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/signed-unsigned vector cast.zig +1-1
...@@ -16,5 +16,5 @@ pub fn main() !void {...@@ -16,5 +16,5 @@ pub fn main() !void {
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// target=native