authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-05 16:49:06+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-05 22:13:57+03:00
logeec2978fac240f6852873bdd9a3ae03b77df6199
tree8a646d9184fff44217ae8de775341a0b497a92cb
parent18440cb239755c983f672b4902147c12e819e029

Sema: better safety check on switch on corrupt value


4 files changed, 17 insertions(+), 10 deletions(-)

src/Sema.zig+8-4
......@@ -9692,7 +9692,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
96929692 }
96939693
96949694 var final_else_body: []const Air.Inst.Index = &.{};
9695 if (special.body.len != 0 or !is_first) {
9695 if (special.body.len != 0 or !is_first or case_block.wantSafety()) {
96969696 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
96979697 defer wip_captures.deinit();
96989698
......@@ -9715,9 +9715,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
97159715 } else {
97169716 // We still need a terminator in this block, but we have proven
97179717 // that it is unreachable.
9718 // TODO this should be a special safety panic other than unreachable, something
9719 // like "panic: switch operand had corrupt value not allowed by the type"
9720 try case_block.addUnreachable(src, true);
9718 if (case_block.wantSafety()) {
9719 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
9720 } else {
9721 _ = try case_block.addNoOp(.unreach);
9722 }
97219723 }
97229724
97239725 try wip_captures.finalize();
......@@ -19970,6 +19972,7 @@ pub const PanicId = enum {
1997019972 /// TODO make this call `std.builtin.panicInactiveUnionField`.
1997119973 inactive_union_field,
1997219974 integer_part_out_of_bounds,
19975 corrupt_switch,
1997319976};
1997419977
1997519978fn addSafetyCheck(
......@@ -20265,6 +20268,7 @@ fn safetyPanic(
2026520268 .exact_division_remainder => "exact division produced remainder",
2026620269 .inactive_union_field => "access of inactive union field",
2026720270 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
20271 .corrupt_switch => "switch on corrupt value",
2026820272 };
2026920273
2027020274 const msg_inst = msg_inst: {
test/behavior/switch.zig+1
......@@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" {
531531test "switch prongs with cases with identical payload types" {
532532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
533533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534535
535536 const Union = union(enum) {
536537 A: usize,
test/cases/safety/switch on corrupted enum value.zig +4-3
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {
5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
1111const E = enum(u32) {
1212 X = 1,
13 Y = 2,
1314};
1415
1516pub fn main() !void {
1617 var e: E = undefined;
1718 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
1819 switch (e) {
19 .X => @breakpoint(),
20 .X, .Y => @breakpoint(),
2021 }
2122 return error.TestFailed;
2223}
2324
2425// run
25// backend=stage1
26// backend=llvm
2627// target=native
test/cases/safety/switch on corrupted union value.zig +4-3
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {
5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
1111const U = union(enum(u32)) {
1212 X: u8,
13 Y: i8,
1314};
1415
1516pub fn main() !void {
1617 var u: U = undefined;
1718 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
1819 switch (u) {
19 .X => @breakpoint(),
20 .X, .Y => @breakpoint(),
2021 }
2122 return error.TestFailed;
2223}
2324
2425// run
25// backend=stage1
26// backend=llvm
2627// target=native