authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-13 23:57:15-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-13 23:57:15-04:00
log802f220739c26081e3018fe7e77e199458ffa8ba
tree442689a62f99e8f0dc64e67e090e95d0aa2a0fda
parentf32928c50dabde1dee40b7137beef0fe72e89b49
parent0cd43b0f8686075cf9bb8b8655ca828bd329d60f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11647 from ziglang/migrate-runtime-safety-tests

migrate runtime safety tests to the new test harness

77 files changed, 1518 insertions(+), 1267 deletions(-)

build.zig+37-37
......@@ -40,10 +40,10 @@ pub fn build(b: *Builder) !void {
4040
4141 const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
4242
43 var test_stage2 = b.addTest("src/test.zig");
44 test_stage2.setBuildMode(mode);
45 test_stage2.addPackagePath("test_cases", "test/cases.zig");
46 test_stage2.single_threaded = single_threaded;
43 var test_cases = b.addTest("src/test.zig");
44 test_cases.setBuildMode(mode);
45 test_cases.addPackagePath("test_cases", "test/cases.zig");
46 test_cases.single_threaded = single_threaded;
4747
4848 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
4949
......@@ -158,7 +158,7 @@ pub fn build(b: *Builder) !void {
158158 if (target.isWindows() and target.getAbi() == .gnu) {
159159 // LTO is currently broken on mingw, this can be removed when it's fixed.
160160 exe.want_lto = false;
161 test_stage2.want_lto = false;
161 test_cases.want_lto = false;
162162 }
163163
164164 const exe_options = b.addOptions();
......@@ -175,7 +175,7 @@ pub fn build(b: *Builder) !void {
175175
176176 if (link_libc) {
177177 exe.linkLibC();
178 test_stage2.linkLibC();
178 test_cases.linkLibC();
179179 }
180180
181181 const is_debug = mode == .Debug;
......@@ -258,7 +258,7 @@ pub fn build(b: *Builder) !void {
258258 zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
259259 zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
260260
261 for ([_]*std.build.LibExeObjStep{ zig0, exe, test_stage2 }) |artifact| {
261 for ([_]*std.build.LibExeObjStep{ zig0, exe, test_cases }) |artifact| {
262262 artifact.addIncludePath("src");
263263 artifact.addIncludePath("deps/SoftFloat-3e/source/include");
264264 artifact.addIncludePath("deps/SoftFloat-3e-prebuilt");
......@@ -335,11 +335,11 @@ pub fn build(b: *Builder) !void {
335335 }
336336
337337 try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
338 try addCmakeCfgOptionsToExe(b, cfg, test_stage2, use_zig_libcxx);
338 try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx);
339339 } else {
340340 // Here we are -Denable-llvm but no cmake integration.
341341 try addStaticLlvmOptionsToExe(exe);
342 try addStaticLlvmOptionsToExe(test_stage2);
342 try addStaticLlvmOptionsToExe(test_cases);
343343 }
344344 }
345345
......@@ -380,34 +380,35 @@ pub fn build(b: *Builder) !void {
380380
381381 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
382382
383 const test_stage2_options = b.addOptions();
384 test_stage2.addOptions("build_options", test_stage2_options);
385
386 test_stage2_options.addOption(bool, "enable_logging", enable_logging);
387 test_stage2_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
388 test_stage2_options.addOption(bool, "skip_non_native", skip_non_native);
389 test_stage2_options.addOption(bool, "skip_stage1", skip_stage1);
390 test_stage2_options.addOption(bool, "is_stage1", is_stage1);
391 test_stage2_options.addOption(bool, "omit_stage2", omit_stage2);
392 test_stage2_options.addOption(bool, "have_llvm", enable_llvm);
393 test_stage2_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
394 test_stage2_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
395 test_stage2_options.addOption(bool, "llvm_has_ve", llvm_has_ve);
396 test_stage2_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
397 test_stage2_options.addOption(bool, "enable_qemu", b.enable_qemu);
398 test_stage2_options.addOption(bool, "enable_wine", b.enable_wine);
399 test_stage2_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
400 test_stage2_options.addOption(bool, "enable_rosetta", b.enable_rosetta);
401 test_stage2_options.addOption(bool, "enable_darling", b.enable_darling);
402 test_stage2_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2);
403 test_stage2_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir);
404 test_stage2_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
405 test_stage2_options.addOption(std.SemanticVersion, "semver", semver);
406
407 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
408 test_stage2_step.dependOn(&test_stage2.step);
383 const test_cases_options = b.addOptions();
384 test_cases.addOptions("build_options", test_cases_options);
385
386 test_cases_options.addOption(bool, "enable_logging", enable_logging);
387 test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
388 test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
389 test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
390 test_cases_options.addOption(bool, "is_stage1", is_stage1);
391 test_cases_options.addOption(bool, "omit_stage2", omit_stage2);
392 test_cases_options.addOption(bool, "have_llvm", enable_llvm);
393 test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
394 test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
395 test_cases_options.addOption(bool, "llvm_has_ve", llvm_has_ve);
396 test_cases_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
397 test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu);
398 test_cases_options.addOption(bool, "enable_wine", b.enable_wine);
399 test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime);
400 test_cases_options.addOption(bool, "enable_rosetta", b.enable_rosetta);
401 test_cases_options.addOption(bool, "enable_darling", b.enable_darling);
402 test_cases_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2);
403 test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir);
404 test_cases_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
405 test_cases_options.addOption(std.SemanticVersion, "semver", semver);
406 test_cases_options.addOption(?[]const u8, "test_filter", test_filter);
407
408 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
409 test_cases_step.dependOn(&test_cases.step);
409410 if (!skip_stage2_tests) {
410 toolchain_step.dependOn(test_stage2_step);
411 toolchain_step.dependOn(test_cases_step);
411412 }
412413
413414 var chosen_modes: [4]builtin.Mode = undefined;
......@@ -485,7 +486,6 @@ pub fn build(b: *Builder) !void {
485486 toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
486487 toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
487488 toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
488 toolchain_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
489489 toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
490490 if (!skip_run_translated_c) {
491491 toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
ci/azure/macos_script+1-2
......@@ -71,12 +71,11 @@ release/bin/zig build test-standalone -Denable-macos-sdk
7171release/bin/zig build test-stack-traces -Denable-macos-sdk
7272release/bin/zig build test-cli -Denable-macos-sdk
7373release/bin/zig build test-asm-link -Denable-macos-sdk
74release/bin/zig build test-runtime-safety -Denable-macos-sdk
7574release/bin/zig build test-translate-c -Denable-macos-sdk
7675release/bin/zig build test-run-translated-c -Denable-macos-sdk
7776release/bin/zig build docs -Denable-macos-sdk
7877release/bin/zig build test-fmt -Denable-macos-sdk
79release/bin/zig build test-stage2 -Denable-macos-sdk
78release/bin/zig build test-cases -Denable-macos-sdk
8079
8180if [ "${BUILD_REASON}" != "PullRequest" ]; then
8281 mv ../LICENSE release/
ci/drone/linux_script_test+1-2
......@@ -34,12 +34,11 @@ case "$1" in
3434 ./build/zig build $BUILD_FLAGS test-stack-traces
3535 ./build/zig build $BUILD_FLAGS test-cli
3636 ./build/zig build $BUILD_FLAGS test-asm-link
37 ./build/zig build $BUILD_FLAGS test-runtime-safety
3837 ./build/zig build $BUILD_FLAGS test-translate-c
3938 ;;
4039 7)
4140 ./build/zig build $BUILD_FLAGS # test building self-hosted without LLVM
42 ./build/zig build $BUILD_FLAGS test-stage2
41 ./build/zig build $BUILD_FLAGS test-cases
4342 ;;
4443 '')
4544 echo "error: expecting test group argument"
ci/zinc/linux_test.sh+1-2
......@@ -69,12 +69,11 @@ $ZIG build test-standalone -fqemu -fwasmtime
6969$ZIG build test-stack-traces -fqemu -fwasmtime
7070$ZIG build test-cli -fqemu -fwasmtime
7171$ZIG build test-asm-link -fqemu -fwasmtime
72$ZIG build test-runtime-safety -fqemu -fwasmtime
7372$ZIG build test-translate-c -fqemu -fwasmtime
7473$ZIG build test-run-translated-c -fqemu -fwasmtime
7574$ZIG build docs -fqemu -fwasmtime
7675$ZIG build test-fmt -fqemu -fwasmtime
77$ZIG build test-stage2 -fqemu -fwasmtime
76$ZIG build test-cases -fqemu -fwasmtime
7877
7978# Produce the experimental std lib documentation.
8079mkdir -p "$RELEASE_STAGING/docs/std"
lib/std/Progress.zig+4-1
......@@ -93,7 +93,9 @@ pub const Node = struct {
9393
9494 /// This is the same as calling `start` and then `end` on the returned `Node`. Thread-safe.
9595 pub fn completeOne(self: *Node) void {
96 self.activate();
96 if (self.parent) |parent| {
97 @atomicStore(?*Node, &parent.recently_updated_child, self, .Release);
98 }
9799 _ = @atomicRmw(usize, &self.unprotected_completed_items, .Add, 1, .Monotonic);
98100 self.context.maybeRefresh();
99101 }
......@@ -120,6 +122,7 @@ pub const Node = struct {
120122 pub fn activate(self: *Node) void {
121123 if (self.parent) |parent| {
122124 @atomicStore(?*Node, &parent.recently_updated_child, self, .Release);
125 self.context.maybeRefresh();
123126 }
124127 }
125128
src/test.zig+24-1
......@@ -1201,6 +1201,9 @@ pub const TestContext = struct {
12011201 if (!build_options.have_llvm and case.backend == .llvm)
12021202 continue;
12031203
1204 if (build_options.test_filter) |test_filter| {
1205 if (std.mem.indexOf(u8, case.name, test_filter) == null) continue;
1206 }
12041207 var prg_node = root_node.start(case.name, case.updates.items.len);
12051208 prg_node.activate();
12061209 defer prg_node.end();
......@@ -1291,6 +1294,8 @@ pub const TestContext = struct {
12911294
12921295 if (case.is_test) {
12931296 try zig_args.append("test");
1297 } else if (update.case == .Execution) {
1298 try zig_args.append("run");
12941299 } else switch (case.output_mode) {
12951300 .Obj => try zig_args.append("build-obj"),
12961301 .Exe => try zig_args.append("build-exe"),
......@@ -1330,6 +1335,7 @@ pub const TestContext = struct {
13301335 }
13311336 },
13321337 else => {
1338 std.debug.print("{s}", .{result.stderr});
13331339 dumpArgs(zig_args.items);
13341340 return error.CompilationCrashed;
13351341 },
......@@ -1394,7 +1400,24 @@ pub const TestContext = struct {
13941400 }
13951401 },
13961402 .CompareObjectFile => @panic("TODO implement in the test harness"),
1397 .Execution => @panic("TODO implement in the test harness"),
1403 .Execution => |expected_stdout| {
1404 switch (result.term) {
1405 .Exited => |code| {
1406 if (code != 0) {
1407 std.debug.print("{s}", .{result.stderr});
1408 dumpArgs(zig_args.items);
1409 return error.CompilationFailed;
1410 }
1411 },
1412 else => {
1413 std.debug.print("{s}", .{result.stderr});
1414 dumpArgs(zig_args.items);
1415 return error.CompilationCrashed;
1416 },
1417 }
1418 try std.testing.expectEqualStrings("", result.stderr);
1419 try std.testing.expectEqualStrings(expected_stdout, result.stdout);
1420 },
13981421 .Header => @panic("TODO implement in the test harness"),
13991422 }
14001423 return;
test/cases/README.md created+61
......@@ -0,0 +1,61 @@
1# Test Case Quick Reference
2
3Use comments at the **end of the file** to indicate metadata about the test
4case. Here are examples of different kinds of tests:
5
6## Compile Error Test
7
8If you want it to be run with `zig test` and match expected error messages:
9
10```zig
11// error
12// is_test=1
13//
14// :4:13: error: 'try' outside function scope
15```
16
17## Execution
18
19This will do `zig run` on the code and expect exit code 0.
20
21```zig
22// run
23```
24
25## Incremental Compilation
26
27Make multiple files that have ".", and then an integer, before the ".zig"
28extension, like this:
29
30```
31hello.0.zig
32hello.1.zig
33hello.2.zig
34```
35
36Each file can be a different kind of test, such as expecting compile errors,
37or expecting to be run and exit(0). The test harness will use these to simulate
38incremental compilation.
39
40At the time of writing there is no way to specify multiple files being changed
41as part of an update.
42
43## Subdirectories
44
45Subdirectories do not have any semantic meaning but they can be used for
46organization since the test harness will recurse into them. The full directory
47path will be prepended as a prefix on the test case name.
48
49## Limiting which Backends and Targets are Tested
50
51```zig
52// run
53// backend=stage2,llvm
54// target=x86_64-linux,x86_64-macos
55```
56
57Possible backends are:
58
59 * `stage1`: equivalent to `-fstage1`.
60 * `stage2`: equivalent to passing `-fno-stage1 -fno-LLVM`.
61 * `llvm`: equivalent to `-fLLVM -fno-stage1`.
test/cases/safety/@alignCast misaligned.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 var array align(4) = [_]u32{0x11111111, 0x11111111};
11 const bytes = std.mem.sliceAsBytes(array[0..]);
12 if (foo(bytes) != 0x11111111) return error.Wrong;
13 return error.TestFailed;
14}
15fn foo(bytes: []u8) u32 {
16 const slice4 = bytes[1..5];
17 const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4));
18 return int_slice[0];
19}
20// run
21// backend=stage1
22// target=native
\ No newline at end of file
test/cases/safety/@asyncCall with too small a frame.zig created+25
......@@ -0,0 +1,25 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
5 _ = message;
6 _ = stack_trace;
7 std.process.exit(0);
8}
9pub fn main() !void {
10 if (builtin.zig_backend == .stage1 and builtin.os.tag == .wasi) {
11 // TODO file a bug for this failure
12 std.process.exit(0); // skip the test
13 }
14 var bytes: [1]u8 align(16) = undefined;
15 var ptr = other;
16 var frame = @asyncCall(&bytes, {}, ptr, .{});
17 _ = frame;
18 return error.TestFailed;
19}
20fn other() callconv(.Async) void {
21 suspend {}
22}
23// run
24// backend=stage1
25// target=native
test/cases/safety/@errSetCast error not present in destination.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8const Set1 = error{A, B};
9const Set2 = error{A, C};
10pub fn main() !void {
11 foo(Set1.B) catch {};
12 return error.TestFailed;
13}
14fn foo(set1: Set1) Set2 {
15 return @errSetCast(Set2, set1);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - negative out of range.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 baz(bar(-129.1));
10 return error.TestFailed;
11}
12fn bar(a: f32) i8 {
13 return @floatToInt(i8, a);
14}
15fn baz(_: i8) void { }
16// run
17// backend=stage1
18// target=native
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 baz(bar(-1.1));
10 return error.TestFailed;
11}
12fn bar(a: f32) u8 {
13 return @floatToInt(u8, a);
14}
15fn baz(_: u8) void { }
16// run
17// backend=stage1
18// target=native
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - positive out of range.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 baz(bar(256.2));
10 return error.TestFailed;
11}
12fn bar(a: f32) u8 {
13 return @floatToInt(u8, a);
14}
15fn baz(_: u8) void { }
16// run
17// backend=stage1
18// target=native
\ No newline at end of file
test/cases/safety/@intCast to u0.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 bar(1, 1);
11 return error.TestFailed;
12}
13
14fn bar(one: u1, not_zero: i32) void {
15 var x = one << @intCast(u0, not_zero);
16 _ = x;
17}
18// run
19// backend=stage1
20// target=native
\ No newline at end of file
test/cases/safety/@intToEnum - no matching tag value.zig created+23
......@@ -0,0 +1,23 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8const Foo = enum {
9 A,
10 B,
11 C,
12};
13pub fn main() !void {
14 baz(bar(3));
15 return error.TestFailed;
16}
17fn bar(a: u2) Foo {
18 return @intToEnum(Foo, a);
19}
20fn baz(_: Foo) void {}
21// run
22// backend=stage1
23// target=native
test/cases/safety/@intToPtr address zero to non-optional byte-aligned pointer.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var zero: usize = 0;
10 var b = @intToPtr(*u8, zero);
11 _ = b;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
test/cases/safety/@intToPtr address zero to non-optional pointer.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var zero: usize = 0;
10 var b = @intToPtr(*i32, zero);
11 _ = b;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
test/cases/safety/@tagName on corrupted enum value.zig created+25
......@@ -0,0 +1,25 @@
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, "invalid enum value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const E = enum(u32) {
12 X = 1,
13};
14
15pub fn main() !void {
16 var e: E = undefined;
17 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 var n = @tagName(e);
19 _ = n;
20 return error.TestFailed;
21}
22
23// run
24// backend=stage1
25// target=native
test/cases/safety/@tagName on corrupted union value.zig created+26
......@@ -0,0 +1,26 @@
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, "invalid enum value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const U = union(enum(u32)) {
12 X: u8,
13};
14
15pub fn main() !void {
16 var u: U = undefined;
17 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
18 var t: @typeInfo(U).Union.tag_type.? = u;
19 var n = @tagName(t);
20 _ = n;
21 return error.TestFailed;
22}
23
24// run
25// backend=stage1
26// target=native
test/cases/safety/array slice sentinel mismatch.zig created+18
......@@ -0,0 +1,18 @@
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, "sentinel mismatch")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 var buf: [4]u8 = undefined;
12 const slice = buf[0..3 :0];
13 _ = slice;
14 return error.TestFailed;
15}
16// run
17// backend=stage1
18// target=native
test/cases/safety/awaiting twice.zig created+29
......@@ -0,0 +1,29 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8var frame: anyframe = undefined;
9
10pub fn main() !void {
11 _ = async amain();
12 resume frame;
13 return error.TestFailed;
14}
15
16fn amain() void {
17 var f = async func();
18 await f;
19 await f;
20}
21
22fn func() void {
23 suspend {
24 frame = @frame();
25 }
26}
27// run
28// backend=stage1
29// target=native
test/cases/safety/bad union field access.zig created+25
......@@ -0,0 +1,25 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9const Foo = union {
10 float: f32,
11 int: u32,
12};
13
14pub fn main() !void {
15 var f = Foo { .int = 42 };
16 bar(&f);
17 return error.TestFailed;
18}
19
20fn bar(f: *Foo) void {
21 f.float = 12.34;
22}
23// run
24// backend=stage1
25// target=native
\ No newline at end of file
test/cases/safety/calling panic.zig created+16
......@@ -0,0 +1,16 @@
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, "oh no")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 if (true) @panic("oh no");
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
\ No newline at end of file
test/cases/safety/cast []u8 to bigger slice of wrong size.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = widenSlice(&[_]u8{1, 2, 3, 4, 5});
11 if (x.len == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
15 return std.mem.bytesAsSlice(i32, slice);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/cast integer to global error and no code matches.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 bar(9999) catch {};
10 return error.TestFailed;
11}
12fn bar(x: u16) anyerror {
13 return @intToError(x);
14}
15// run
16// backend=stage1
17// target=native
\ No newline at end of file
test/cases/safety/empty slice with sentinel out of bounds.zig created+21
......@@ -0,0 +1,21 @@
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, "index out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf_zero = [0]u8{};
13 const input: []u8 = &buf_zero;
14 const slice = input[0..0 :0];
15 _ = slice;
16 return error.TestFailed;
17}
18
19// run
20// backend=stage1
21// target=native
test/cases/safety/error return trace across suspend points.zig created+39
......@@ -0,0 +1,39 @@
1const std = @import("std");
2
3
4pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
5 _ = message;
6 _ = stack_trace;
7 std.process.exit(0);
8}
9
10var failing_frame: @Frame(failing) = undefined;
11
12pub fn main() !void {
13 const p = nonFailing();
14 resume p;
15 const p2 = async printTrace(p);
16 _ = p2;
17 return error.TestFailed;
18}
19
20fn nonFailing() anyframe->anyerror!void {
21 failing_frame = async failing();
22 return &failing_frame;
23}
24
25fn failing() anyerror!void {
26 suspend {}
27 return second();
28}
29
30fn second() callconv(.Async) anyerror!void {
31 return error.Fail;
32}
33
34fn printTrace(p: anyframe->anyerror!void) void {
35 (await p) catch unreachable;
36}
37// run
38// backend=stage1
39// target=native
\ No newline at end of file
test/cases/safety/exact division failure - vectors.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
11 var b: @Vector(4, i32) = [4]i32{111, 222, 333, 441};
12 const x = divExact(a, b);
13 _ = x;
14 return error.TestFailed;
15}
16fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
17 return @divExact(a, b);
18}
19// run
20// backend=stage1
21// target=native
\ No newline at end of file
test/cases/safety/exact division failure.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = divExact(10, 3);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn divExact(a: i32, b: i32) i32 {
15 return @divExact(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/intToPtr with misaligned address.zig created+18
......@@ -0,0 +1,18 @@
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, "incorrect alignment")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 var x: usize = 5;
12 var y = @intToPtr([*]align(4) u8, x);
13 _ = y;
14 return error.TestFailed;
15}
16// run
17// backend=stage1
18// target=native
test/cases/safety/integer addition overflow.zig created+23
......@@ -0,0 +1,23 @@
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, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 const x = add(65530, 10);
13 if (x == 0) return error.Whatever;
14 return error.TestFailed;
15}
16
17fn add(a: u16, b: u16) u16 {
18 return a + b;
19}
20
21// run
22// backend=stage1
23// target=native
test/cases/safety/integer division by zero - vectors.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
10 var b: @Vector(4, i32) = [4]i32{111, 0, 333, 444};
11 const x = div0(a, b);
12 _ = x;
13 return error.TestFailed;
14}
15fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
16 return @divTrunc(a, b);
17}
18// run
19// backend=stage1
20// target=native
\ No newline at end of file
test/cases/safety/integer division by zero.zig created+18
......@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 const x = div0(999, 0);
10 _ = x;
11 return error.TestFailed;
12}
13fn div0(a: i32, b: i32) i32 {
14 return @divTrunc(a, b);
15}
16// run
17// backend=stage1
18// target=native
\ No newline at end of file
test/cases/safety/integer multiplication overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = mul(300, 6000);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn mul(a: u16, b: u16) u16 {
15 return a * b;
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/integer negation overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = neg(-32768);
11 if (x == 32767) return error.Whatever;
12 return error.TestFailed;
13}
14fn neg(a: i16) i16 {
15 return -a;
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/integer subtraction overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = sub(10, 20);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn sub(a: u16, b: u16) u16 {
15 return a - b;
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/invalid resume of async function.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var p = async suspendOnce();
10 resume p; //ok
11 resume p; //bad
12 return error.TestFailed;
13}
14fn suspendOnce() void {
15 suspend {}
16}
17// run
18// backend=stage1
19// target=native
test/cases/safety/nosuspend function call, callee suspends.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 _ = nosuspend add(101, 100);
10 return error.TestFailed;
11}
12fn add(a: i32, b: i32) i32 {
13 if (a > 100) {
14 suspend {}
15 }
16 return a + b;
17}
18// run
19// backend=stage1
20// target=native
test/cases/safety/optional unwrap operator on C pointer.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var ptr: [*c]i32 = null;
10 var b = ptr.?;
11 _ = b;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
test/cases/safety/optional unwrap operator on null pointer.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var ptr: ?*i32 = null;
10 var b = ptr.?;
11 _ = b;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
test/cases/safety/out of bounds slice access.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 const a = [_]i32{1, 2, 3, 4};
10 baz(bar(&a));
11 return error.TestFailed;
12}
13fn bar(a: []const i32) i32 {
14 return a[4];
15}
16fn baz(_: i32) void { }
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/pointer casting null to non-optional pointer.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var c_ptr: [*c]u8 = 0;
10 var zig_ptr: *u8 = c_ptr;
11 _ = zig_ptr;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
test/cases/safety/pointer slice sentinel mismatch.zig created+21
......@@ -0,0 +1,21 @@
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, "sentinel mismatch")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf: [4]u8 = undefined;
13 const ptr: [*]u8 = &buf;
14 const slice = ptr[0..3 :0];
15 _ = slice;
16 return error.TestFailed;
17}
18
19// run
20// backend=stage1
21// target=native
test/cases/safety/resuming a function which is awaiting a call.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var frame = async first();
10 resume frame;
11 return error.TestFailed;
12}
13fn first() void {
14 other();
15}
16fn other() void {
17 suspend {}
18}
19// run
20// backend=stage1
21// target=native
test/cases/safety/resuming a function which is awaiting a frame.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var frame = async first();
10 resume frame;
11 return error.TestFailed;
12}
13fn first() void {
14 var frame = async other();
15 await frame;
16}
17fn other() void {
18 suspend {}
19}
20// run
21// backend=stage1
22// target=native
test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig created+32
......@@ -0,0 +1,32 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8fn foo() void {
9 suspend {
10 global_frame = @frame();
11 }
12 var f = async bar(@frame());
13 _ = f;
14 std.os.exit(1);
15}
16
17fn bar(frame: anyframe) void {
18 suspend {
19 resume frame;
20 }
21 std.os.exit(1);
22}
23
24var global_frame: anyframe = undefined;
25pub fn main() !void {
26 _ = async foo();
27 resume global_frame;
28 std.os.exit(1);
29}
30// run
31// backend=stage1
32// target=native
test/cases/safety/resuming a non-suspended function which never been suspended.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8fn foo() void {
9 var f = async bar(@frame());
10 _ = f;
11 std.os.exit(1);
12}
13
14fn bar(frame: anyframe) void {
15 suspend {
16 resume frame;
17 }
18 std.os.exit(1);
19}
20
21pub fn main() !void {
22 _ = async foo();
23 return error.TestFailed;
24}
25// run
26// backend=stage1
27// target=native
test/cases/safety/shift left by huge amount.zig created+21
......@@ -0,0 +1,21 @@
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, "shift amount is greater than the type size")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var x: u24 = 42;
13 var y: u5 = 24;
14 var z = x >> y;
15 _ = z;
16 return error.TestFailed;
17}
18
19// run
20// backend=stage1
21// target=native
test/cases/safety/shift right by huge amount.zig created+21
......@@ -0,0 +1,21 @@
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, "shift amount is greater than the type size")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var x: u24 = 42;
13 var y: u5 = 24;
14 var z = x << y;
15 _ = z;
16 return error.TestFailed;
17}
18
19// run
20// backend=stage1
21// target=native
test/cases/safety/signed integer division overflow - vectors.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 var a: @Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 };
11 var b: @Vector(4, i16) = [_]i16{ 1, 2, -1, 4 };
12 const x = div(a, b);
13 if (x[2] == 32767) return error.Whatever;
14 return error.TestFailed;
15}
16fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
17 return @divTrunc(a, b);
18}
19// run
20// backend=stage1
21// target=native
\ No newline at end of file
test/cases/safety/signed integer division overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = div(-32768, -1);
11 if (x == 32767) return error.Whatever;
12 return error.TestFailed;
13}
14fn div(a: i16, b: i16) i16 {
15 return @divTrunc(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var value: c_short = -1;
10 var casted = @intCast(u32, value);
11 _ = casted;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
\ No newline at end of file
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = unsigned_cast(-10);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn unsigned_cast(x: i32) u32 {
15 return @intCast(u32, x);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/signed shift left overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shl(-16385, 1);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shl(a: i16, b: u4) i16 {
15 return @shlExact(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/signed shift right overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shr(-16385, 1);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shr(a: i16, b: u4) i16 {
15 return @shrExact(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/signed-unsigned vector cast.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, "attempt to cast negative value to unsigned integer")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var x = @splat(4, @as(i32, -2147483647));
13 var y = @intCast(@Vector(4, u32), x);
14 _ = y;
15 return error.TestFailed;
16}
17
18// run
19// backend=stage1
20// target=native
test/cases/safety/slice sentinel mismatch - floats.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, "sentinel mismatch")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf: [4]f32 = undefined;
13 const slice = buf[0..3 :1.2];
14 _ = slice;
15 return error.TestFailed;
16}
17
18// run
19// backend=stage1
20// target=native
test/cases/safety/slice sentinel mismatch - optional pointers.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, "sentinel mismatch")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf: [4]?*i32 = undefined;
13 const slice = buf[0..3 :null];
14 _ = slice;
15 return error.TestFailed;
16}
17
18// run
19// backend=stage1
20// target=native
test/cases/safety/slice slice sentinel mismatch.zig created+19
......@@ -0,0 +1,19 @@
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, "sentinel mismatch")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 var buf: [4]u8 = undefined;
12 const slice = buf[0..];
13 const slice2 = slice[0..3 :0];
14 _ = slice2;
15 return error.TestFailed;
16}
17// run
18// backend=stage1
19// target=native
test/cases/safety/slice with sentinel out of bounds.zig created+21
......@@ -0,0 +1,21 @@
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, "index out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf = [4]u8{ 'a', 'b', 'c', 0 };
13 const input: []u8 = &buf;
14 const slice = input[0..4 :0];
15 _ = slice;
16 return error.TestFailed;
17}
18
19// run
20// backend=stage1
21// target=native
test/cases/safety/slicing null C pointer.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 var ptr: [*c]const u32 = null;
11 var slice = ptr[0..3];
12 _ = slice;
13 return error.TestFailed;
14}
15// run
16// backend=stage1
17// target=native
\ No newline at end of file
test/cases/safety/switch on corrupted enum value.zig created+26
......@@ -0,0 +1,26 @@
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, "reached unreachable code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const E = enum(u32) {
12 X = 1,
13};
14
15pub fn main() !void {
16 var e: E = undefined;
17 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 switch (e) {
19 .X => @breakpoint(),
20 }
21 return error.TestFailed;
22}
23
24// run
25// backend=stage1
26// target=native
test/cases/safety/switch on corrupted union value.zig created+26
......@@ -0,0 +1,26 @@
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, "reached unreachable code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const U = union(enum(u32)) {
12 X: u8,
13};
14
15pub fn main() !void {
16 var u: U = undefined;
17 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
18 switch (u) {
19 .X => @breakpoint(),
20 }
21 return error.TestFailed;
22}
23
24// run
25// backend=stage1
26// target=native
test/cases/safety/truncating vector cast.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, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var x = @splat(4, @as(u32, 0xdeadbeef));
13 var y = @intCast(@Vector(4, u16), x);
14 _ = y;
15 return error.TestFailed;
16}
17
18// run
19// backend=stage1
20// target=native
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var value: u8 = 245;
10 var casted = @intCast(i8, value);
11 _ = casted;
12 return error.TestFailed;
13}
14// run
15// backend=stage1
16// target=native
\ No newline at end of file
test/cases/safety/unsigned shift left overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shl(0b0010111111111111, 3);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shl(a: u16, b: u4) u16 {
15 return @shlExact(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/unsigned shift right overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shr(0b0010111111111111, 3);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shr(a: u16, b: u4) u16 {
15 return @shrExact(a, b);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/unsigned-signed vector cast.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, "integer cast truncated bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var x = @splat(4, @as(u32, 0x80000000));
13 var y = @intCast(@Vector(4, i32), x);
14 _ = y;
15 return error.TestFailed;
16}
17
18// run
19// backend=stage1
20// target=native
test/cases/safety/unwrap error.zig created+19
......@@ -0,0 +1,19 @@
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, "attempt to unwrap error: Whatever")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 bar() catch unreachable;
12 return error.TestFailed;
13}
14fn bar() !void {
15 return error.Whatever;
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/value does not fit in shortening cast - u0.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shorten_cast(1);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shorten_cast(x: u8) u0 {
15 return @intCast(u0, x);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/value does not fit in shortening cast.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8
9pub fn main() !void {
10 const x = shorten_cast(200);
11 if (x == 0) return error.Whatever;
12 return error.TestFailed;
13}
14fn shorten_cast(x: i32) i8 {
15 return @intCast(i8, x);
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/vector integer addition overflow.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };
10 var b: @Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
11 const x = add(a, b);
12 _ = x;
13 return error.TestFailed;
14}
15fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
16 return a + b;
17}
18// run
19// backend=stage1
20// target=native
\ No newline at end of file
test/cases/safety/vector integer multiplication overflow.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };
10 var b: @Vector(4, u8) = [_]u8{ 5, 6, 2, 8 };
11 const x = mul(b, a);
12 _ = x;
13 return error.TestFailed;
14}
15fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
16 return a * b;
17}
18// run
19// backend=stage1
20// target=native
\ No newline at end of file
test/cases/safety/vector integer negation overflow.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
10 const x = neg(a);
11 _ = x;
12 return error.TestFailed;
13}
14fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
15 return -a;
16}
17// run
18// backend=stage1
19// target=native
\ No newline at end of file
test/cases/safety/vector integer subtraction overflow.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 _ = message;
5 _ = stack_trace;
6 std.process.exit(0);
7}
8pub fn main() !void {
9 var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };
10 var b: @Vector(4, u32) = [_]u32{ 5, 6, 7, 8 };
11 const x = sub(b, a);
12 _ = x;
13 return error.TestFailed;
14}
15fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
16 return a - b;
17}
18// run
19// backend=stage1
20// target=native
\ No newline at end of file
test/runtime_safety.zig deleted-1206
......@@ -1,1206 +0,0 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: *tests.CompareOutputContext) void {
4 {
5 const check_panic_msg =
6 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
7 \\ _ = stack_trace;
8 \\ if (std.mem.eql(u8, message, "reached unreachable code")) {
9 \\ std.process.exit(126); // good
10 \\ }
11 \\ std.process.exit(0); // test failed
12 \\}
13 ;
14
15 cases.addRuntimeSafety("switch on corrupted enum value",
16 \\const std = @import("std");
17 ++ check_panic_msg ++
18 \\const E = enum(u32) {
19 \\ X = 1,
20 \\};
21 \\pub fn main() void {
22 \\ var e: E = undefined;
23 \\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
24 \\ switch (e) {
25 \\ .X => @breakpoint(),
26 \\ }
27 \\}
28 );
29
30 cases.addRuntimeSafety("switch on corrupted union value",
31 \\const std = @import("std");
32 ++ check_panic_msg ++
33 \\const U = union(enum(u32)) {
34 \\ X: u8,
35 \\};
36 \\pub fn main() void {
37 \\ var u: U = undefined;
38 \\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
39 \\ switch (u) {
40 \\ .X => @breakpoint(),
41 \\ }
42 \\}
43 );
44 }
45
46 {
47 const check_panic_msg =
48 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
49 \\ _ = stack_trace;
50 \\ if (std.mem.eql(u8, message, "invalid enum value")) {
51 \\ std.process.exit(126); // good
52 \\ }
53 \\ std.process.exit(0); // test failed
54 \\}
55 ;
56
57 cases.addRuntimeSafety("@tagName on corrupted enum value",
58 \\const std = @import("std");
59 ++ check_panic_msg ++
60 \\const E = enum(u32) {
61 \\ X = 1,
62 \\};
63 \\pub fn main() void {
64 \\ var e: E = undefined;
65 \\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
66 \\ var n = @tagName(e);
67 \\ _ = n;
68 \\}
69 );
70
71 cases.addRuntimeSafety("@tagName on corrupted union value",
72 \\const std = @import("std");
73 ++ check_panic_msg ++
74 \\const U = union(enum(u32)) {
75 \\ X: u8,
76 \\};
77 \\pub fn main() void {
78 \\ var u: U = undefined;
79 \\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
80 \\ var t: @typeInfo(U).Union.tag_type.? = u;
81 \\ var n = @tagName(t);
82 \\ _ = n;
83 \\}
84 );
85 }
86
87 {
88 const check_panic_msg =
89 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
90 \\ _ = stack_trace;
91 \\ if (std.mem.eql(u8, message, "index out of bounds")) {
92 \\ std.process.exit(126); // good
93 \\ }
94 \\ std.process.exit(0); // test failed
95 \\}
96 ;
97
98 cases.addRuntimeSafety("slice with sentinel out of bounds",
99 \\const std = @import("std");
100 ++ check_panic_msg ++
101 \\pub fn main() void {
102 \\ var buf = [4]u8{'a','b','c',0};
103 \\ const input: []u8 = &buf;
104 \\ const slice = input[0..4 :0];
105 \\ _ = slice;
106 \\}
107 );
108 cases.addRuntimeSafety("empty slice with sentinel out of bounds",
109 \\const std = @import("std");
110 ++ check_panic_msg ++
111 \\pub fn main() void {
112 \\ var buf_zero = [0]u8{};
113 \\ const input: []u8 = &buf_zero;
114 \\ const slice = input[0..0 :0];
115 \\ _ = slice;
116 \\}
117 );
118 }
119
120 cases.addRuntimeSafety("truncating vector cast",
121 \\const std = @import("std");
122 \\const V = @import("std").meta.Vector;
123 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
124 \\ _ = stack_trace;
125 \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
126 \\ std.process.exit(126); // good
127 \\ }
128 \\ std.process.exit(0); // test failed
129 \\}
130 \\pub fn main() void {
131 \\ var x = @splat(4, @as(u32, 0xdeadbeef));
132 \\ var y = @intCast(V(4, u16), x);
133 \\ _ = y;
134 \\}
135 );
136
137 cases.addRuntimeSafety("unsigned-signed vector cast",
138 \\const std = @import("std");
139 \\const V = @import("std").meta.Vector;
140 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
141 \\ _ = stack_trace;
142 \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
143 \\ std.process.exit(126); // good
144 \\ }
145 \\ std.process.exit(0); // test failed
146 \\}
147 \\pub fn main() void {
148 \\ var x = @splat(4, @as(u32, 0x80000000));
149 \\ var y = @intCast(V(4, i32), x);
150 \\ _ = y;
151 \\}
152 );
153
154 cases.addRuntimeSafety("signed-unsigned vector cast",
155 \\const std = @import("std");
156 \\const V = @import("std").meta.Vector;
157 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
158 \\ _ = stack_trace;
159 \\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
160 \\ std.process.exit(126); // good
161 \\ }
162 \\ std.process.exit(0); // test failed
163 \\}
164 \\pub fn main() void {
165 \\ var x = @splat(4, @as(i32, -2147483647));
166 \\ var y = @intCast(V(4, u32), x);
167 \\ _ = y;
168 \\}
169 );
170
171 cases.addRuntimeSafety("shift left by huge amount",
172 \\const std = @import("std");
173 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
174 \\ _ = stack_trace;
175 \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
176 \\ std.process.exit(126); // good
177 \\ }
178 \\ std.process.exit(0); // test failed
179 \\}
180 \\pub fn main() void {
181 \\ var x: u24 = 42;
182 \\ var y: u5 = 24;
183 \\ var z = x >> y;
184 \\ _ = z;
185 \\}
186 );
187
188 cases.addRuntimeSafety("shift right by huge amount",
189 \\const std = @import("std");
190 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
191 \\ _ = stack_trace;
192 \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
193 \\ std.process.exit(126); // good
194 \\ }
195 \\ std.process.exit(0); // test failed
196 \\}
197 \\pub fn main() void {
198 \\ var x: u24 = 42;
199 \\ var y: u5 = 24;
200 \\ var z = x << y;
201 \\ _ = z;
202 \\}
203 );
204
205 cases.addRuntimeSafety("slice sentinel mismatch - optional pointers",
206 \\const std = @import("std");
207 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
208 \\ _ = stack_trace;
209 \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
210 \\ std.process.exit(126); // good
211 \\ }
212 \\ std.process.exit(0); // test failed
213 \\}
214 \\pub fn main() void {
215 \\ var buf: [4]?*i32 = undefined;
216 \\ const slice = buf[0..3 :null];
217 \\ _ = slice;
218 \\}
219 );
220
221 cases.addRuntimeSafety("slice sentinel mismatch - floats",
222 \\const std = @import("std");
223 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
224 \\ _ = stack_trace;
225 \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
226 \\ std.process.exit(126); // good
227 \\ }
228 \\ std.process.exit(0); // test failed
229 \\}
230 \\pub fn main() void {
231 \\ var buf: [4]f32 = undefined;
232 \\ const slice = buf[0..3 :1.2];
233 \\ _ = slice;
234 \\}
235 );
236
237 cases.addRuntimeSafety("pointer slice sentinel mismatch",
238 \\const std = @import("std");
239 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
240 \\ _ = stack_trace;
241 \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
242 \\ std.process.exit(126); // good
243 \\ }
244 \\ std.process.exit(0); // test failed
245 \\}
246 \\pub fn main() void {
247 \\ var buf: [4]u8 = undefined;
248 \\ const ptr: [*]u8 = &buf;
249 \\ const slice = ptr[0..3 :0];
250 \\ _ = slice;
251 \\}
252 );
253
254 cases.addRuntimeSafety("slice slice sentinel mismatch",
255 \\const std = @import("std");
256 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
257 \\ _ = stack_trace;
258 \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
259 \\ std.process.exit(126); // good
260 \\ }
261 \\ std.process.exit(0); // test failed
262 \\}
263 \\pub fn main() void {
264 \\ var buf: [4]u8 = undefined;
265 \\ const slice = buf[0..];
266 \\ const slice2 = slice[0..3 :0];
267 \\ _ = slice2;
268 \\}
269 );
270
271 cases.addRuntimeSafety("array slice sentinel mismatch",
272 \\const std = @import("std");
273 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
274 \\ _ = stack_trace;
275 \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
276 \\ std.process.exit(126); // good
277 \\ }
278 \\ std.process.exit(0); // test failed
279 \\}
280 \\pub fn main() void {
281 \\ var buf: [4]u8 = undefined;
282 \\ const slice = buf[0..3 :0];
283 \\ _ = slice;
284 \\}
285 );
286
287 cases.addRuntimeSafety("intToPtr with misaligned address",
288 \\const std = @import("std");
289 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
290 \\ _ = stack_trace;
291 \\ if (std.mem.eql(u8, message, "incorrect alignment")) {
292 \\ std.os.exit(126); // good
293 \\ }
294 \\ std.os.exit(0); // test failed
295 \\}
296 \\pub fn main() void {
297 \\ var x: usize = 5;
298 \\ var y = @intToPtr([*]align(4) u8, x);
299 \\ _ = y;
300 \\}
301 );
302
303 cases.addRuntimeSafety("resuming a non-suspended function which never been suspended",
304 \\const std = @import("std");
305 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
306 \\ _ = message;
307 \\ _ = stack_trace;
308 \\ std.os.exit(126);
309 \\}
310 \\fn foo() void {
311 \\ var f = async bar(@frame());
312 \\ _ = f;
313 \\ std.os.exit(0);
314 \\}
315 \\
316 \\fn bar(frame: anyframe) void {
317 \\ suspend {
318 \\ resume frame;
319 \\ }
320 \\ std.os.exit(0);
321 \\}
322 \\
323 \\pub fn main() void {
324 \\ _ = async foo();
325 \\}
326 );
327
328 cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed",
329 \\const std = @import("std");
330 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
331 \\ _ = message;
332 \\ _ = stack_trace;
333 \\ std.os.exit(126);
334 \\}
335 \\fn foo() void {
336 \\ suspend {
337 \\ global_frame = @frame();
338 \\ }
339 \\ var f = async bar(@frame());
340 \\ _ = f;
341 \\ std.os.exit(0);
342 \\}
343 \\
344 \\fn bar(frame: anyframe) void {
345 \\ suspend {
346 \\ resume frame;
347 \\ }
348 \\ std.os.exit(0);
349 \\}
350 \\
351 \\var global_frame: anyframe = undefined;
352 \\pub fn main() void {
353 \\ _ = async foo();
354 \\ resume global_frame;
355 \\ std.os.exit(0);
356 \\}
357 );
358
359 cases.addRuntimeSafety("nosuspend function call, callee suspends",
360 \\const std = @import("std");
361 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
362 \\ _ = message;
363 \\ _ = stack_trace;
364 \\ std.os.exit(126);
365 \\}
366 \\pub fn main() void {
367 \\ _ = nosuspend add(101, 100);
368 \\}
369 \\fn add(a: i32, b: i32) i32 {
370 \\ if (a > 100) {
371 \\ suspend {}
372 \\ }
373 \\ return a + b;
374 \\}
375 );
376
377 cases.addRuntimeSafety("awaiting twice",
378 \\const std = @import("std");
379 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
380 \\ _ = message;
381 \\ _ = stack_trace;
382 \\ std.os.exit(126);
383 \\}
384 \\var frame: anyframe = undefined;
385 \\
386 \\pub fn main() void {
387 \\ _ = async amain();
388 \\ resume frame;
389 \\}
390 \\
391 \\fn amain() void {
392 \\ var f = async func();
393 \\ await f;
394 \\ await f;
395 \\}
396 \\
397 \\fn func() void {
398 \\ suspend {
399 \\ frame = @frame();
400 \\ }
401 \\}
402 );
403
404 cases.addRuntimeSafety("@asyncCall with too small a frame",
405 \\const std = @import("std");
406 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
407 \\ _ = message;
408 \\ _ = stack_trace;
409 \\ std.os.exit(126);
410 \\}
411 \\pub fn main() void {
412 \\ var bytes: [1]u8 align(16) = undefined;
413 \\ var ptr = other;
414 \\ var frame = @asyncCall(&bytes, {}, ptr, .{});
415 \\ _ = frame;
416 \\}
417 \\fn other() callconv(.Async) void {
418 \\ suspend {}
419 \\}
420 );
421
422 cases.addRuntimeSafety("resuming a function which is awaiting a frame",
423 \\const std = @import("std");
424 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
425 \\ _ = message;
426 \\ _ = stack_trace;
427 \\ std.os.exit(126);
428 \\}
429 \\pub fn main() void {
430 \\ var frame = async first();
431 \\ resume frame;
432 \\}
433 \\fn first() void {
434 \\ var frame = async other();
435 \\ await frame;
436 \\}
437 \\fn other() void {
438 \\ suspend {}
439 \\}
440 );
441
442 cases.addRuntimeSafety("resuming a function which is awaiting a call",
443 \\const std = @import("std");
444 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
445 \\ _ = message;
446 \\ _ = stack_trace;
447 \\ std.os.exit(126);
448 \\}
449 \\pub fn main() void {
450 \\ var frame = async first();
451 \\ resume frame;
452 \\}
453 \\fn first() void {
454 \\ other();
455 \\}
456 \\fn other() void {
457 \\ suspend {}
458 \\}
459 );
460
461 cases.addRuntimeSafety("invalid resume of async function",
462 \\const std = @import("std");
463 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
464 \\ _ = message;
465 \\ _ = stack_trace;
466 \\ std.os.exit(126);
467 \\}
468 \\pub fn main() void {
469 \\ var p = async suspendOnce();
470 \\ resume p; //ok
471 \\ resume p; //bad
472 \\}
473 \\fn suspendOnce() void {
474 \\ suspend {}
475 \\}
476 );
477
478 cases.addRuntimeSafety(".? operator on null pointer",
479 \\const std = @import("std");
480 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
481 \\ _ = message;
482 \\ _ = stack_trace;
483 \\ std.os.exit(126);
484 \\}
485 \\pub fn main() void {
486 \\ var ptr: ?*i32 = null;
487 \\ var b = ptr.?;
488 \\ _ = b;
489 \\}
490 );
491
492 cases.addRuntimeSafety(".? operator on C pointer",
493 \\const std = @import("std");
494 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
495 \\ _ = message;
496 \\ _ = stack_trace;
497 \\ std.os.exit(126);
498 \\}
499 \\pub fn main() void {
500 \\ var ptr: [*c]i32 = null;
501 \\ var b = ptr.?;
502 \\ _ = b;
503 \\}
504 );
505
506 cases.addRuntimeSafety("@intToPtr address zero to non-optional pointer",
507 \\const std = @import("std");
508 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
509 \\ _ = message;
510 \\ _ = stack_trace;
511 \\ std.os.exit(126);
512 \\}
513 \\pub fn main() void {
514 \\ var zero: usize = 0;
515 \\ var b = @intToPtr(*i32, zero);
516 \\ _ = b;
517 \\}
518 );
519
520 cases.addRuntimeSafety("@intToPtr address zero to non-optional byte-aligned pointer",
521 \\const std = @import("std");
522 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
523 \\ _ = message;
524 \\ _ = stack_trace;
525 \\ std.os.exit(126);
526 \\}
527 \\pub fn main() void {
528 \\ var zero: usize = 0;
529 \\ var b = @intToPtr(*u8, zero);
530 \\ _ = b;
531 \\}
532 );
533
534 cases.addRuntimeSafety("pointer casting null to non-optional pointer",
535 \\const std = @import("std");
536 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
537 \\ _ = message;
538 \\ _ = stack_trace;
539 \\ std.os.exit(126);
540 \\}
541 \\pub fn main() void {
542 \\ var c_ptr: [*c]u8 = 0;
543 \\ var zig_ptr: *u8 = c_ptr;
544 \\ _ = zig_ptr;
545 \\}
546 );
547
548 cases.addRuntimeSafety("@intToEnum - no matching tag value",
549 \\const std = @import("std");
550 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
551 \\ _ = message;
552 \\ _ = stack_trace;
553 \\ std.os.exit(126);
554 \\}
555 \\const Foo = enum {
556 \\ A,
557 \\ B,
558 \\ C,
559 \\};
560 \\pub fn main() void {
561 \\ baz(bar(3));
562 \\}
563 \\fn bar(a: u2) Foo {
564 \\ return @intToEnum(Foo, a);
565 \\}
566 \\fn baz(_: Foo) void {}
567 );
568
569 cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned",
570 \\const std = @import("std");
571 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
572 \\ _ = message;
573 \\ _ = stack_trace;
574 \\ std.os.exit(126);
575 \\}
576 \\pub fn main() void {
577 \\ baz(bar(-1.1));
578 \\}
579 \\fn bar(a: f32) u8 {
580 \\ return @floatToInt(u8, a);
581 \\}
582 \\fn baz(_: u8) void { }
583 );
584
585 cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range",
586 \\const std = @import("std");
587 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
588 \\ _ = message;
589 \\ _ = stack_trace;
590 \\ std.os.exit(126);
591 \\}
592 \\pub fn main() void {
593 \\ baz(bar(-129.1));
594 \\}
595 \\fn bar(a: f32) i8 {
596 \\ return @floatToInt(i8, a);
597 \\}
598 \\fn baz(_: i8) void { }
599 );
600
601 cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range",
602 \\const std = @import("std");
603 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
604 \\ _ = message;
605 \\ _ = stack_trace;
606 \\ std.os.exit(126);
607 \\}
608 \\pub fn main() void {
609 \\ baz(bar(256.2));
610 \\}
611 \\fn bar(a: f32) u8 {
612 \\ return @floatToInt(u8, a);
613 \\}
614 \\fn baz(_: u8) void { }
615 );
616
617 cases.addRuntimeSafety("calling panic",
618 \\const std = @import("std");
619 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
620 \\ _ = message;
621 \\ _ = stack_trace;
622 \\ std.os.exit(126);
623 \\}
624 \\pub fn main() void {
625 \\ @panic("oh no");
626 \\}
627 );
628
629 cases.addRuntimeSafety("out of bounds slice access",
630 \\const std = @import("std");
631 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
632 \\ _ = message;
633 \\ _ = stack_trace;
634 \\ std.os.exit(126);
635 \\}
636 \\pub fn main() void {
637 \\ const a = [_]i32{1, 2, 3, 4};
638 \\ baz(bar(&a));
639 \\}
640 \\fn bar(a: []const i32) i32 {
641 \\ return a[4];
642 \\}
643 \\fn baz(_: i32) void { }
644 );
645
646 cases.addRuntimeSafety("integer addition overflow",
647 \\const std = @import("std");
648 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
649 \\ _ = message;
650 \\ _ = stack_trace;
651 \\ std.os.exit(126);
652 \\}
653 \\pub fn main() !void {
654 \\ const x = add(65530, 10);
655 \\ if (x == 0) return error.Whatever;
656 \\}
657 \\fn add(a: u16, b: u16) u16 {
658 \\ return a + b;
659 \\}
660 );
661
662 cases.addRuntimeSafety("vector integer addition overflow",
663 \\const std = @import("std");
664 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
665 \\ _ = message;
666 \\ _ = stack_trace;
667 \\ std.os.exit(126);
668 \\}
669 \\pub fn main() void {
670 \\ var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };
671 \\ var b: @Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
672 \\ const x = add(a, b);
673 \\ _ = x;
674 \\}
675 \\fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
676 \\ return a + b;
677 \\}
678 );
679
680 cases.addRuntimeSafety("vector integer subtraction overflow",
681 \\const std = @import("std");
682 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
683 \\ _ = message;
684 \\ _ = stack_trace;
685 \\ std.os.exit(126);
686 \\}
687 \\pub fn main() void {
688 \\ var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };
689 \\ var b: @Vector(4, u32) = [_]u32{ 5, 6, 7, 8 };
690 \\ const x = sub(b, a);
691 \\ _ = x;
692 \\}
693 \\fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
694 \\ return a - b;
695 \\}
696 );
697
698 cases.addRuntimeSafety("vector integer multiplication overflow",
699 \\const std = @import("std");
700 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
701 \\ _ = message;
702 \\ _ = stack_trace;
703 \\ std.os.exit(126);
704 \\}
705 \\pub fn main() void {
706 \\ var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };
707 \\ var b: @Vector(4, u8) = [_]u8{ 5, 6, 2, 8 };
708 \\ const x = mul(b, a);
709 \\ _ = x;
710 \\}
711 \\fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
712 \\ return a * b;
713 \\}
714 );
715
716 cases.addRuntimeSafety("vector integer negation overflow",
717 \\const std = @import("std");
718 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
719 \\ _ = message;
720 \\ _ = stack_trace;
721 \\ std.os.exit(126);
722 \\}
723 \\pub fn main() void {
724 \\ var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
725 \\ const x = neg(a);
726 \\ _ = x;
727 \\}
728 \\fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
729 \\ return -a;
730 \\}
731 );
732
733 cases.addRuntimeSafety("integer subtraction overflow",
734 \\const std = @import("std");
735 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
736 \\ _ = message;
737 \\ _ = stack_trace;
738 \\ std.os.exit(126);
739 \\}
740 \\pub fn main() !void {
741 \\ const x = sub(10, 20);
742 \\ if (x == 0) return error.Whatever;
743 \\}
744 \\fn sub(a: u16, b: u16) u16 {
745 \\ return a - b;
746 \\}
747 );
748
749 cases.addRuntimeSafety("integer multiplication overflow",
750 \\const std = @import("std");
751 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
752 \\ _ = message;
753 \\ _ = stack_trace;
754 \\ std.os.exit(126);
755 \\}
756 \\pub fn main() !void {
757 \\ const x = mul(300, 6000);
758 \\ if (x == 0) return error.Whatever;
759 \\}
760 \\fn mul(a: u16, b: u16) u16 {
761 \\ return a * b;
762 \\}
763 );
764
765 cases.addRuntimeSafety("integer negation overflow",
766 \\const std = @import("std");
767 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
768 \\ _ = message;
769 \\ _ = stack_trace;
770 \\ std.os.exit(126);
771 \\}
772 \\pub fn main() !void {
773 \\ const x = neg(-32768);
774 \\ if (x == 32767) return error.Whatever;
775 \\}
776 \\fn neg(a: i16) i16 {
777 \\ return -a;
778 \\}
779 );
780
781 cases.addRuntimeSafety("signed integer division overflow",
782 \\const std = @import("std");
783 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
784 \\ _ = message;
785 \\ _ = stack_trace;
786 \\ std.os.exit(126);
787 \\}
788 \\pub fn main() !void {
789 \\ const x = div(-32768, -1);
790 \\ if (x == 32767) return error.Whatever;
791 \\}
792 \\fn div(a: i16, b: i16) i16 {
793 \\ return @divTrunc(a, b);
794 \\}
795 );
796
797 cases.addRuntimeSafety("signed integer division overflow - vectors",
798 \\const std = @import("std");
799 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
800 \\ _ = message;
801 \\ _ = stack_trace;
802 \\ std.os.exit(126);
803 \\}
804 \\pub fn main() !void {
805 \\ var a: @Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 };
806 \\ var b: @Vector(4, i16) = [_]i16{ 1, 2, -1, 4 };
807 \\ const x = div(a, b);
808 \\ if (x[2] == 32767) return error.Whatever;
809 \\}
810 \\fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
811 \\ return @divTrunc(a, b);
812 \\}
813 );
814
815 cases.addRuntimeSafety("signed shift left overflow",
816 \\const std = @import("std");
817 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
818 \\ _ = message;
819 \\ _ = stack_trace;
820 \\ std.os.exit(126);
821 \\}
822 \\pub fn main() !void {
823 \\ const x = shl(-16385, 1);
824 \\ if (x == 0) return error.Whatever;
825 \\}
826 \\fn shl(a: i16, b: u4) i16 {
827 \\ return @shlExact(a, b);
828 \\}
829 );
830
831 cases.addRuntimeSafety("unsigned shift left overflow",
832 \\const std = @import("std");
833 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
834 \\ _ = message;
835 \\ _ = stack_trace;
836 \\ std.os.exit(126);
837 \\}
838 \\pub fn main() !void {
839 \\ const x = shl(0b0010111111111111, 3);
840 \\ if (x == 0) return error.Whatever;
841 \\}
842 \\fn shl(a: u16, b: u4) u16 {
843 \\ return @shlExact(a, b);
844 \\}
845 );
846
847 cases.addRuntimeSafety("signed shift right overflow",
848 \\const std = @import("std");
849 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
850 \\ _ = message;
851 \\ _ = stack_trace;
852 \\ std.os.exit(126);
853 \\}
854 \\pub fn main() !void {
855 \\ const x = shr(-16385, 1);
856 \\ if (x == 0) return error.Whatever;
857 \\}
858 \\fn shr(a: i16, b: u4) i16 {
859 \\ return @shrExact(a, b);
860 \\}
861 );
862
863 cases.addRuntimeSafety("unsigned shift right overflow",
864 \\const std = @import("std");
865 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
866 \\ _ = message;
867 \\ _ = stack_trace;
868 \\ std.os.exit(126);
869 \\}
870 \\pub fn main() !void {
871 \\ const x = shr(0b0010111111111111, 3);
872 \\ if (x == 0) return error.Whatever;
873 \\}
874 \\fn shr(a: u16, b: u4) u16 {
875 \\ return @shrExact(a, b);
876 \\}
877 );
878
879 cases.addRuntimeSafety("integer division by zero",
880 \\const std = @import("std");
881 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
882 \\ _ = message;
883 \\ _ = stack_trace;
884 \\ std.os.exit(126);
885 \\}
886 \\pub fn main() void {
887 \\ const x = div0(999, 0);
888 \\ _ = x;
889 \\}
890 \\fn div0(a: i32, b: i32) i32 {
891 \\ return @divTrunc(a, b);
892 \\}
893 );
894
895 cases.addRuntimeSafety("integer division by zero - vectors",
896 \\const std = @import("std");
897 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
898 \\ _ = message;
899 \\ _ = stack_trace;
900 \\ std.os.exit(126);
901 \\}
902 \\pub fn main() void {
903 \\ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
904 \\ var b: @Vector(4, i32) = [4]i32{111, 0, 333, 444};
905 \\ const x = div0(a, b);
906 \\ _ = x;
907 \\}
908 \\fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
909 \\ return @divTrunc(a, b);
910 \\}
911 );
912
913 cases.addRuntimeSafety("exact division failure",
914 \\const std = @import("std");
915 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
916 \\ _ = message;
917 \\ _ = stack_trace;
918 \\ std.os.exit(126);
919 \\}
920 \\pub fn main() !void {
921 \\ const x = divExact(10, 3);
922 \\ if (x == 0) return error.Whatever;
923 \\}
924 \\fn divExact(a: i32, b: i32) i32 {
925 \\ return @divExact(a, b);
926 \\}
927 );
928
929 cases.addRuntimeSafety("exact division failure - vectors",
930 \\const std = @import("std");
931 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
932 \\ _ = message;
933 \\ _ = stack_trace;
934 \\ std.os.exit(126);
935 \\}
936 \\pub fn main() !void {
937 \\ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
938 \\ var b: @Vector(4, i32) = [4]i32{111, 222, 333, 441};
939 \\ const x = divExact(a, b);
940 \\ _ = x;
941 \\}
942 \\fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
943 \\ return @divExact(a, b);
944 \\}
945 );
946
947 cases.addRuntimeSafety("cast []u8 to bigger slice of wrong size",
948 \\const std = @import("std");
949 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
950 \\ _ = message;
951 \\ _ = stack_trace;
952 \\ std.os.exit(126);
953 \\}
954 \\pub fn main() !void {
955 \\ const x = widenSlice(&[_]u8{1, 2, 3, 4, 5});
956 \\ if (x.len == 0) return error.Whatever;
957 \\}
958 \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
959 \\ return std.mem.bytesAsSlice(i32, slice);
960 \\}
961 );
962
963 cases.addRuntimeSafety("value does not fit in shortening cast",
964 \\const std = @import("std");
965 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
966 \\ _ = message;
967 \\ _ = stack_trace;
968 \\ std.os.exit(126);
969 \\}
970 \\pub fn main() !void {
971 \\ const x = shorten_cast(200);
972 \\ if (x == 0) return error.Whatever;
973 \\}
974 \\fn shorten_cast(x: i32) i8 {
975 \\ return @intCast(i8, x);
976 \\}
977 );
978
979 cases.addRuntimeSafety("value does not fit in shortening cast - u0",
980 \\const std = @import("std");
981 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
982 \\ _ = message;
983 \\ _ = stack_trace;
984 \\ std.os.exit(126);
985 \\}
986 \\pub fn main() !void {
987 \\ const x = shorten_cast(1);
988 \\ if (x == 0) return error.Whatever;
989 \\}
990 \\fn shorten_cast(x: u8) u0 {
991 \\ return @intCast(u0, x);
992 \\}
993 );
994
995 cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer",
996 \\const std = @import("std");
997 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
998 \\ _ = message;
999 \\ _ = stack_trace;
1000 \\ std.os.exit(126);
1001 \\}
1002 \\pub fn main() !void {
1003 \\ const x = unsigned_cast(-10);
1004 \\ if (x == 0) return error.Whatever;
1005 \\}
1006 \\fn unsigned_cast(x: i32) u32 {
1007 \\ return @intCast(u32, x);
1008 \\}
1009 );
1010
1011 cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening",
1012 \\const std = @import("std");
1013 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1014 \\ _ = message;
1015 \\ _ = stack_trace;
1016 \\ std.os.exit(126);
1017 \\}
1018 \\pub fn main() void {
1019 \\ var value: c_short = -1;
1020 \\ var casted = @intCast(u32, value);
1021 \\ _ = casted;
1022 \\}
1023 );
1024
1025 cases.addRuntimeSafety("unsigned integer not fitting in cast to signed integer - same bit count",
1026 \\const std = @import("std");
1027 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1028 \\ _ = message;
1029 \\ _ = stack_trace;
1030 \\ std.os.exit(126);
1031 \\}
1032 \\pub fn main() void {
1033 \\ var value: u8 = 245;
1034 \\ var casted = @intCast(i8, value);
1035 \\ _ = casted;
1036 \\}
1037 );
1038
1039 cases.addRuntimeSafety("unwrap error",
1040 \\const std = @import("std");
1041 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1042 \\ _ = stack_trace;
1043 \\ if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
1044 \\ std.os.exit(126); // good
1045 \\ }
1046 \\ std.os.exit(0); // test failed
1047 \\}
1048 \\pub fn main() void {
1049 \\ bar() catch unreachable;
1050 \\}
1051 \\fn bar() !void {
1052 \\ return error.Whatever;
1053 \\}
1054 );
1055
1056 cases.addRuntimeSafety("cast integer to global error and no code matches",
1057 \\const std = @import("std");
1058 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1059 \\ _ = message;
1060 \\ _ = stack_trace;
1061 \\ std.os.exit(126);
1062 \\}
1063 \\pub fn main() void {
1064 \\ bar(9999) catch {};
1065 \\}
1066 \\fn bar(x: u16) anyerror {
1067 \\ return @intToError(x);
1068 \\}
1069 );
1070
1071 cases.addRuntimeSafety("@errSetCast error not present in destination",
1072 \\const std = @import("std");
1073 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1074 \\ _ = message;
1075 \\ _ = stack_trace;
1076 \\ std.os.exit(126);
1077 \\}
1078 \\const Set1 = error{A, B};
1079 \\const Set2 = error{A, C};
1080 \\pub fn main() void {
1081 \\ foo(Set1.B) catch {};
1082 \\}
1083 \\fn foo(set1: Set1) Set2 {
1084 \\ return @errSetCast(Set2, set1);
1085 \\}
1086 );
1087
1088 cases.addRuntimeSafety("@alignCast misaligned",
1089 \\const std = @import("std");
1090 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1091 \\ _ = message;
1092 \\ _ = stack_trace;
1093 \\ std.os.exit(126);
1094 \\}
1095 \\pub fn main() !void {
1096 \\ var array align(4) = [_]u32{0x11111111, 0x11111111};
1097 \\ const bytes = std.mem.sliceAsBytes(array[0..]);
1098 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
1099 \\}
1100 \\fn foo(bytes: []u8) u32 {
1101 \\ const slice4 = bytes[1..5];
1102 \\ const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4));
1103 \\ return int_slice[0];
1104 \\}
1105 );
1106
1107 cases.addRuntimeSafety("bad union field access",
1108 \\const std = @import("std");
1109 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1110 \\ _ = message;
1111 \\ _ = stack_trace;
1112 \\ std.os.exit(126);
1113 \\}
1114 \\
1115 \\const Foo = union {
1116 \\ float: f32,
1117 \\ int: u32,
1118 \\};
1119 \\
1120 \\pub fn main() void {
1121 \\ var f = Foo { .int = 42 };
1122 \\ bar(&f);
1123 \\}
1124 \\
1125 \\fn bar(f: *Foo) void {
1126 \\ f.float = 12.34;
1127 \\}
1128 );
1129
1130 // @intCast a runtime integer to u0 actually results in a comptime-known value,
1131 // but we still emit a safety check to ensure the integer was 0 and thus
1132 // did not truncate information.
1133 cases.addRuntimeSafety("@intCast to u0",
1134 \\const std = @import("std");
1135 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1136 \\ _ = message;
1137 \\ _ = stack_trace;
1138 \\ std.os.exit(126);
1139 \\}
1140 \\
1141 \\pub fn main() void {
1142 \\ bar(1, 1);
1143 \\}
1144 \\
1145 \\fn bar(one: u1, not_zero: i32) void {
1146 \\ var x = one << @intCast(u0, not_zero);
1147 \\ _ = x;
1148 \\}
1149 );
1150
1151 // This case makes sure that the code compiles and runs. There is not actually a special
1152 // runtime safety check having to do specifically with error return traces across suspend points.
1153 cases.addRuntimeSafety("error return trace across suspend points",
1154 \\const std = @import("std");
1155 \\
1156 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1157 \\ _ = message;
1158 \\ _ = stack_trace;
1159 \\ std.os.exit(126);
1160 \\}
1161 \\
1162 \\var failing_frame: @Frame(failing) = undefined;
1163 \\
1164 \\pub fn main() void {
1165 \\ const p = nonFailing();
1166 \\ resume p;
1167 \\ const p2 = async printTrace(p);
1168 \\ _ = p2;
1169 \\}
1170 \\
1171 \\fn nonFailing() anyframe->anyerror!void {
1172 \\ failing_frame = async failing();
1173 \\ return &failing_frame;
1174 \\}
1175 \\
1176 \\fn failing() anyerror!void {
1177 \\ suspend {}
1178 \\ return second();
1179 \\}
1180 \\
1181 \\fn second() callconv(.Async) anyerror!void {
1182 \\ return error.Fail;
1183 \\}
1184 \\
1185 \\fn printTrace(p: anyframe->anyerror!void) void {
1186 \\ (await p) catch unreachable;
1187 \\}
1188 );
1189
1190 // Slicing a C pointer returns a non-allowzero slice, thus we need to emit
1191 // a safety check to ensure the pointer is not null.
1192 cases.addRuntimeSafety("slicing null C pointer",
1193 \\const std = @import("std");
1194 \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
1195 \\ _ = message;
1196 \\ _ = stack_trace;
1197 \\ std.os.exit(126);
1198 \\}
1199 \\
1200 \\pub fn main() void {
1201 \\ var ptr: [*c]const u32 = null;
1202 \\ var slice = ptr[0..3];
1203 \\ _ = slice;
1204 \\}
1205 );
1206}
test/tests.zig-16
......@@ -18,7 +18,6 @@ const compare_output = @import("compare_output.zig");
1818const standalone = @import("standalone.zig");
1919const stack_traces = @import("stack_traces.zig");
2020const assemble_and_link = @import("assemble_and_link.zig");
21const runtime_safety = @import("runtime_safety.zig");
2221const translate_c = @import("translate_c.zig");
2322const run_translated_c = @import("run_translated_c.zig");
2423const gen_h = @import("gen_h.zig");
......@@ -455,21 +454,6 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []
455454 return cases.step;
456455}
457456
458pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
459 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
460 cases.* = CompareOutputContext{
461 .b = b,
462 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
463 .test_index = 0,
464 .test_filter = test_filter,
465 .modes = modes,
466 };
467
468 runtime_safety.addCases(cases);
469
470 return cases.step;
471}
472
473457pub fn addStandaloneTests(
474458 b: *build.Builder,
475459 test_filter: ?[]const u8,