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...@@ -9692,7 +9692,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9692 }9692 }
96939693
9694 var final_else_body: []const Air.Inst.Index = &.{};9694 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()) {
9696 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);9696 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
9697 defer wip_captures.deinit();9697 defer wip_captures.deinit();
96989698
...@@ -9715,9 +9715,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9715,9 +9715,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9715 } else {9715 } else {
9716 // We still need a terminator in this block, but we have proven9716 // We still need a terminator in this block, but we have proven
9717 // that it is unreachable.9717 // that it is unreachable.
9718 // TODO this should be a special safety panic other than unreachable, something9718 if (case_block.wantSafety()) {
9719 // like "panic: switch operand had corrupt value not allowed by the type"9719 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
9720 try case_block.addUnreachable(src, true);9720 } else {
9721 _ = try case_block.addNoOp(.unreach);
9722 }
9721 }9723 }
97229724
9723 try wip_captures.finalize();9725 try wip_captures.finalize();
...@@ -19970,6 +19972,7 @@ pub const PanicId = enum {...@@ -19970,6 +19972,7 @@ pub const PanicId = enum {
19970 /// TODO make this call `std.builtin.panicInactiveUnionField`.19972 /// TODO make this call `std.builtin.panicInactiveUnionField`.
19971 inactive_union_field,19973 inactive_union_field,
19972 integer_part_out_of_bounds,19974 integer_part_out_of_bounds,
19975 corrupt_switch,
19973};19976};
1997419977
19975fn addSafetyCheck(19978fn addSafetyCheck(
...@@ -20265,6 +20268,7 @@ fn safetyPanic(...@@ -20265,6 +20268,7 @@ fn safetyPanic(
20265 .exact_division_remainder => "exact division produced remainder",20268 .exact_division_remainder => "exact division produced remainder",
20266 .inactive_union_field => "access of inactive union field",20269 .inactive_union_field => "access of inactive union field",
20267 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",20270 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
20271 .corrupt_switch => "switch on corrupt value",
20268 };20272 };
2026920273
20270 const msg_inst = msg_inst: {20274 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" {...@@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" {
531test "switch prongs with cases with identical payload types" {531test "switch prongs with cases with identical payload types" {
532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534535
535 const Union = union(enum) {536 const Union = union(enum) {
536 A: usize,537 A: usize,
test/cases/safety/switch on corrupted enum value.zig +4-3
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const 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 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const E = enum(u32) {11const E = enum(u32) {
12 X = 1,12 X = 1,
13 Y = 2,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
16 var e: E = undefined;17 var e: E = undefined;
17 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 switch (e) {19 switch (e) {
19 .X => @breakpoint(),20 .X, .Y => @breakpoint(),
20 }21 }
21 return error.TestFailed;22 return error.TestFailed;
22}23}
2324
24// run25// run
25// backend=stage126// backend=llvm
26// target=native27// target=native
test/cases/safety/switch on corrupted union value.zig +4-3
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const 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 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const U = union(enum(u32)) {11const U = union(enum(u32)) {
12 X: u8,12 X: u8,
13 Y: i8,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
16 var u: U = undefined;17 var u: U = undefined;
17 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));18 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
18 switch (u) {19 switch (u) {
19 .X => @breakpoint(),20 .X, .Y => @breakpoint(),
20 }21 }
21 return error.TestFailed;22 return error.TestFailed;
22}23}
2324
24// run25// run
25// backend=stage126// backend=llvm
26// target=native27// target=native