Commit 66f3efb63b
Changed files (76)
ci
src
test
cases
safety
ci/azure/macos_script
@@ -71,12 +71,11 @@ release/bin/zig build test-standalone -Denable-macos-sdk
release/bin/zig build test-stack-traces -Denable-macos-sdk
release/bin/zig build test-cli -Denable-macos-sdk
release/bin/zig build test-asm-link -Denable-macos-sdk
-release/bin/zig build test-runtime-safety -Denable-macos-sdk
release/bin/zig build test-translate-c -Denable-macos-sdk
release/bin/zig build test-run-translated-c -Denable-macos-sdk
release/bin/zig build docs -Denable-macos-sdk
release/bin/zig build test-fmt -Denable-macos-sdk
-release/bin/zig build test-stage2 -Denable-macos-sdk
+release/bin/zig build test-cases -Denable-macos-sdk
if [ "${BUILD_REASON}" != "PullRequest" ]; then
mv ../LICENSE release/
ci/drone/linux_script_test
@@ -34,12 +34,11 @@ case "$1" in
./build/zig build $BUILD_FLAGS test-stack-traces
./build/zig build $BUILD_FLAGS test-cli
./build/zig build $BUILD_FLAGS test-asm-link
- ./build/zig build $BUILD_FLAGS test-runtime-safety
./build/zig build $BUILD_FLAGS test-translate-c
;;
7)
./build/zig build $BUILD_FLAGS # test building self-hosted without LLVM
- ./build/zig build $BUILD_FLAGS test-stage2
+ ./build/zig build $BUILD_FLAGS test-cases
;;
'')
echo "error: expecting test group argument"
ci/zinc/linux_test.sh
@@ -69,12 +69,11 @@ $ZIG build test-standalone -fqemu -fwasmtime
$ZIG build test-stack-traces -fqemu -fwasmtime
$ZIG build test-cli -fqemu -fwasmtime
$ZIG build test-asm-link -fqemu -fwasmtime
-$ZIG build test-runtime-safety -fqemu -fwasmtime
$ZIG build test-translate-c -fqemu -fwasmtime
$ZIG build test-run-translated-c -fqemu -fwasmtime
$ZIG build docs -fqemu -fwasmtime
$ZIG build test-fmt -fqemu -fwasmtime
-$ZIG build test-stage2 -fqemu -fwasmtime
+$ZIG build test-cases -fqemu -fwasmtime
# Produce the experimental std lib documentation.
mkdir -p "$RELEASE_STAGING/docs/std"
src/test.zig
@@ -1394,7 +1394,22 @@ pub const TestContext = struct {
}
},
.CompareObjectFile => @panic("TODO implement in the test harness"),
- .Execution => @panic("TODO implement in the test harness"),
+ .Execution => |expected_stdout| {
+ switch (result.term) {
+ .Exited => |code| {
+ if (code != 0) {
+ dumpArgs(zig_args.items);
+ return error.CompilationFailed;
+ }
+ },
+ else => {
+ dumpArgs(zig_args.items);
+ return error.CompilationCrashed;
+ },
+ }
+ try std.testing.expectEqualStrings("", result.stderr);
+ try std.testing.expectEqualStrings(expected_stdout, result.stdout);
+ },
.Header => @panic("TODO implement in the test harness"),
}
return;
test/cases/safety/@alignCast misaligned.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ var array align(4) = [_]u32{0x11111111, 0x11111111};
+ const bytes = std.mem.sliceAsBytes(array[0..]);
+ if (foo(bytes) != 0x11111111) return error.Wrong;
+ return error.TestFailed;
+}
+fn foo(bytes: []u8) u32 {
+ const slice4 = bytes[1..5];
+ const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4));
+ return int_slice[0];
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@asyncCall with too small a frame.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var bytes: [1]u8 align(16) = undefined;
+ var ptr = other;
+ var frame = @asyncCall(&bytes, {}, ptr, .{});
+ _ = frame;
+ return error.TestFailed;
+}
+fn other() callconv(.Async) void {
+ suspend {}
+}
+// run
+// backend=stage1
test/cases/safety/@errSetCast error not present in destination.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+const Set1 = error{A, B};
+const Set2 = error{A, C};
+pub fn main() !void {
+ foo(Set1.B) catch {};
+ return error.TestFailed;
+}
+fn foo(set1: Set1) Set2 {
+ return @errSetCast(Set2, set1);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - negative out of range.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ baz(bar(-129.1));
+ return error.TestFailed;
+}
+fn bar(a: f32) i8 {
+ return @floatToInt(i8, a);
+}
+fn baz(_: i8) void { }
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ baz(bar(-1.1));
+ return error.TestFailed;
+}
+fn bar(a: f32) u8 {
+ return @floatToInt(u8, a);
+}
+fn baz(_: u8) void { }
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@floatToInt cannot fit - positive out of range.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ baz(bar(256.2));
+ return error.TestFailed;
+}
+fn bar(a: f32) u8 {
+ return @floatToInt(u8, a);
+}
+fn baz(_: u8) void { }
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@intCast to u0.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ bar(1, 1);
+ return error.TestFailed;
+}
+
+fn bar(one: u1, not_zero: i32) void {
+ var x = one << @intCast(u0, not_zero);
+ _ = x;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/@intToEnum - no matching tag value.zig
@@ -0,0 +1,22 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+const Foo = enum {
+ A,
+ B,
+ C,
+};
+pub fn main() !void {
+ baz(bar(3));
+ return error.TestFailed;
+}
+fn bar(a: u2) Foo {
+ return @intToEnum(Foo, a);
+}
+fn baz(_: Foo) void {}
+// run
+// backend=stage1
test/cases/safety/@intToPtr address zero to non-optional byte-aligned pointer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var zero: usize = 0;
+ var b = @intToPtr(*u8, zero);
+ _ = b;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/@intToPtr address zero to non-optional pointer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var zero: usize = 0;
+ var b = @intToPtr(*i32, zero);
+ _ = b;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/@tagName on corrupted enum value.zig
@@ -0,0 +1,24 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "invalid enum value")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+const E = enum(u32) {
+ X = 1,
+};
+
+pub fn main() !void {
+ var e: E = undefined;
+ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
+ var n = @tagName(e);
+ _ = n;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/@tagName on corrupted union value.zig
@@ -0,0 +1,25 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "invalid enum value")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+const U = union(enum(u32)) {
+ X: u8,
+};
+
+pub fn main() !void {
+ var u: U = undefined;
+ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
+ var t: @typeInfo(U).Union.tag_type.? = u;
+ var n = @tagName(t);
+ _ = n;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/array slice sentinel mismatch.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "sentinel mismatch")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+pub fn main() !void {
+ var buf: [4]u8 = undefined;
+ const slice = buf[0..3 :0];
+ _ = slice;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
+
test/cases/safety/awaiting twice.zig
@@ -0,0 +1,28 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+var frame: anyframe = undefined;
+
+pub fn main() !void {
+ _ = async amain();
+ resume frame;
+ return error.TestFailed;
+}
+
+fn amain() void {
+ var f = async func();
+ await f;
+ await f;
+}
+
+fn func() void {
+ suspend {
+ frame = @frame();
+ }
+}
+// run
+// backend=stage1
test/cases/safety/bad union field access.zig
@@ -0,0 +1,24 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+const Foo = union {
+ float: f32,
+ int: u32,
+};
+
+pub fn main() !void {
+ var f = Foo { .int = 42 };
+ bar(&f);
+ return error.TestFailed;
+}
+
+fn bar(f: *Foo) void {
+ f.float = 12.34;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/calling panic.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "oh no")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+pub fn main() !void {
+ if (true) @panic("oh no");
+ return error.TestFailed;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/cast []u8 to bigger slice of wrong size.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = widenSlice(&[_]u8{1, 2, 3, 4, 5});
+ if (x.len == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
+ return std.mem.bytesAsSlice(i32, slice);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/cast integer to global error and no code matches.zig
@@ -0,0 +1,16 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ bar(9999) catch {};
+ return error.TestFailed;
+}
+fn bar(x: u16) anyerror {
+ return @intToError(x);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/empty slice with sentinel out of bounds.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "index out of bounds")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf_zero = [0]u8{};
+ const input: []u8 = &buf_zero;
+ const slice = input[0..0 :0];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/error return trace across suspend points.zig
@@ -0,0 +1,38 @@
+const std = @import("std");
+
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+var failing_frame: @Frame(failing) = undefined;
+
+pub fn main() !void {
+ const p = nonFailing();
+ resume p;
+ const p2 = async printTrace(p);
+ _ = p2;
+ return error.TestFailed;
+}
+
+fn nonFailing() anyframe->anyerror!void {
+ failing_frame = async failing();
+ return &failing_frame;
+}
+
+fn failing() anyerror!void {
+ suspend {}
+ return second();
+}
+
+fn second() callconv(.Async) anyerror!void {
+ return error.Fail;
+}
+
+fn printTrace(p: anyframe->anyerror!void) void {
+ (await p) catch unreachable;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/exact division failure - vectors.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
+ var b: @Vector(4, i32) = [4]i32{111, 222, 333, 441};
+ const x = divExact(a, b);
+ _ = x;
+ return error.TestFailed;
+}
+fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
+ return @divExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/exact division failure.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = divExact(10, 3);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn divExact(a: i32, b: i32) i32 {
+ return @divExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/integer addition overflow.zig
@@ -0,0 +1,22 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "integer overflow")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ const x = add(65530, 10);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+
+fn add(a: u16, b: u16) u16 {
+ return a + b;
+}
+
+// run
+// backend=stage1
test/cases/safety/integer division by zero - vectors.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
+ var b: @Vector(4, i32) = [4]i32{111, 0, 333, 444};
+ const x = div0(a, b);
+ _ = x;
+ return error.TestFailed;
+}
+fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
+ return @divTrunc(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/integer division by zero.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ const x = div0(999, 0);
+ _ = x;
+ return error.TestFailed;
+}
+fn div0(a: i32, b: i32) i32 {
+ return @divTrunc(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/integer multiplication overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = mul(300, 6000);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn mul(a: u16, b: u16) u16 {
+ return a * b;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/integer negation overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = neg(-32768);
+ if (x == 32767) return error.Whatever;
+ return error.TestFailed;
+}
+fn neg(a: i16) i16 {
+ return -a;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/integer subtraction overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = sub(10, 20);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn sub(a: u16, b: u16) u16 {
+ return a - b;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/intToPtr with misaligned address.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "incorrect alignment")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+pub fn main() !void {
+ var x: usize = 5;
+ var y = @intToPtr([*]align(4) u8, x);
+ _ = y;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/invalid resume of async function.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var p = async suspendOnce();
+ resume p; //ok
+ resume p; //bad
+ return error.TestFailed;
+}
+fn suspendOnce() void {
+ suspend {}
+}
+// run
+// backend=stage1
test/cases/safety/nosuspend function call, callee suspends.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ _ = nosuspend add(101, 100);
+ return error.TestFailed;
+}
+fn add(a: i32, b: i32) i32 {
+ if (a > 100) {
+ suspend {}
+ }
+ return a + b;
+}
+// run
+// backend=stage1
test/cases/safety/optional unwrap operator on C pointer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var ptr: [*c]i32 = null;
+ var b = ptr.?;
+ _ = b;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/optional unwrap operator on null pointer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var ptr: ?*i32 = null;
+ var b = ptr.?;
+ _ = b;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/out of bounds slice access.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ const a = [_]i32{1, 2, 3, 4};
+ baz(bar(&a));
+ return error.TestFailed;
+}
+fn bar(a: []const i32) i32 {
+ return a[4];
+}
+fn baz(_: i32) void { }
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/pointer casting null to non-optional pointer.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var c_ptr: [*c]u8 = 0;
+ var zig_ptr: *u8 = c_ptr;
+ _ = zig_ptr;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/pointer slice sentinel mismatch.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "sentinel mismatch")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf: [4]u8 = undefined;
+ const ptr: [*]u8 = &buf;
+ const slice = ptr[0..3 :0];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/resuming a function which is awaiting a call.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var frame = async first();
+ resume frame;
+ return error.TestFailed;
+}
+fn first() void {
+ other();
+}
+fn other() void {
+ suspend {}
+}
+// run
+// backend=stage1
test/cases/safety/resuming a function which is awaiting a frame.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var frame = async first();
+ resume frame;
+ return error.TestFailed;
+}
+fn first() void {
+ var frame = async other();
+ await frame;
+}
+fn other() void {
+ suspend {}
+}
+// run
+// backend=stage1
test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig
@@ -0,0 +1,31 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+fn foo() void {
+ suspend {
+ global_frame = @frame();
+ }
+ var f = async bar(@frame());
+ _ = f;
+ std.os.exit(1);
+}
+
+fn bar(frame: anyframe) void {
+ suspend {
+ resume frame;
+ }
+ std.os.exit(1);
+}
+
+var global_frame: anyframe = undefined;
+pub fn main() !void {
+ _ = async foo();
+ resume global_frame;
+ std.os.exit(1);
+}
+// run
+// backend=stage1
test/cases/safety/resuming a non-suspended function which never been suspended.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+fn foo() void {
+ var f = async bar(@frame());
+ _ = f;
+ std.os.exit(1);
+}
+
+fn bar(frame: anyframe) void {
+ suspend {
+ resume frame;
+ }
+ std.os.exit(1);
+}
+
+pub fn main() !void {
+ _ = async foo();
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/shift left by huge amount.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var x: u24 = 42;
+ var y: u5 = 24;
+ var z = x >> y;
+ _ = z;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/shift right by huge amount.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var x: u24 = 42;
+ var y: u5 = 24;
+ var z = x << y;
+ _ = z;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/signed integer division overflow - vectors.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ var a: @Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 };
+ var b: @Vector(4, i16) = [_]i16{ 1, 2, -1, 4 };
+ const x = div(a, b);
+ if (x[2] == 32767) return error.Whatever;
+ return error.TestFailed;
+}
+fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
+ return @divTrunc(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed integer division overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = div(-32768, -1);
+ if (x == 32767) return error.Whatever;
+ return error.TestFailed;
+}
+fn div(a: i16, b: i16) i16 {
+ return @divTrunc(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var value: c_short = -1;
+ var casted = @intCast(u32, value);
+ _ = casted;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = unsigned_cast(-10);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn unsigned_cast(x: i32) u32 {
+ return @intCast(u32, x);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed shift left overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shl(-16385, 1);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shl(a: i16, b: u4) i16 {
+ return @shlExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed shift right overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shr(-16385, 1);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shr(a: i16, b: u4) i16 {
+ return @shrExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/signed-unsigned vector cast.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var x = @splat(4, @as(i32, -2147483647));
+ var y = @intCast(@Vector(4, u32), x);
+ _ = y;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/slice sentinel mismatch - floats.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "sentinel mismatch")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf: [4]f32 = undefined;
+ const slice = buf[0..3 :1.2];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/slice sentinel mismatch - optional pointers.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "sentinel mismatch")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf: [4]?*i32 = undefined;
+ const slice = buf[0..3 :null];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/slice slice sentinel mismatch.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "sentinel mismatch")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+pub fn main() !void {
+ var buf: [4]u8 = undefined;
+ const slice = buf[0..];
+ const slice2 = slice[0..3 :0];
+ _ = slice2;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
test/cases/safety/slice with sentinel out of bounds.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "index out of bounds")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var buf = [4]u8{ 'a', 'b', 'c', 0 };
+ const input: []u8 = &buf;
+ const slice = input[0..4 :0];
+ _ = slice;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/slicing null C pointer.zig
@@ -0,0 +1,16 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ var ptr: [*c]const u32 = null;
+ var slice = ptr[0..3];
+ _ = slice;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/switch on corrupted enum value.zig
@@ -0,0 +1,25 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "reached unreachable code")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+const E = enum(u32) {
+ X = 1,
+};
+
+pub fn main() !void {
+ var e: E = undefined;
+ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
+ switch (e) {
+ .X => @breakpoint(),
+ }
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/switch on corrupted union value.zig
@@ -0,0 +1,25 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "reached unreachable code")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+const U = union(enum(u32)) {
+ X: u8,
+};
+
+pub fn main() !void {
+ var u: U = undefined;
+ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
+ switch (u) {
+ .X => @breakpoint(),
+ }
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/truncating vector cast.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var x = @splat(4, @as(u32, 0xdeadbeef));
+ var y = @intCast(@Vector(4, u16), x);
+ _ = y;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var value: u8 = 245;
+ var casted = @intCast(i8, value);
+ _ = casted;
+ return error.TestFailed;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/unsigned shift left overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shl(0b0010111111111111, 3);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shl(a: u16, b: u4) u16 {
+ return @shlExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/unsigned shift right overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shr(0b0010111111111111, 3);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shr(a: u16, b: u4) u16 {
+ return @shrExact(a, b);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/unsigned-signed vector cast.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+pub fn main() !void {
+ var x = @splat(4, @as(u32, 0x80000000));
+ var y = @intCast(@Vector(4, i32), x);
+ _ = y;
+ return error.TestFailed;
+}
+
+// run
+// backend=stage1
test/cases/safety/unwrap error.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+pub fn main() !void {
+ bar() catch unreachable;
+ return error.TestFailed;
+}
+fn bar() !void {
+ return error.Whatever;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/value does not fit in shortening cast - u0.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shorten_cast(1);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shorten_cast(x: u8) u0 {
+ return @intCast(u0, x);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/value does not fit in shortening cast.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+
+pub fn main() !void {
+ const x = shorten_cast(200);
+ if (x == 0) return error.Whatever;
+ return error.TestFailed;
+}
+fn shorten_cast(x: i32) i8 {
+ return @intCast(i8, x);
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/vector integer addition overflow.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };
+ var b: @Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
+ const x = add(a, b);
+ _ = x;
+ return error.TestFailed;
+}
+fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
+ return a + b;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/vector integer multiplication overflow.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };
+ var b: @Vector(4, u8) = [_]u8{ 5, 6, 2, 8 };
+ const x = mul(b, a);
+ _ = x;
+ return error.TestFailed;
+}
+fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
+ return a * b;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/vector integer negation overflow.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
+ const x = neg(a);
+ _ = x;
+ return error.TestFailed;
+}
+fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
+ return -a;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/safety/vector integer subtraction overflow.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
+ _ = message;
+ _ = stack_trace;
+ std.process.exit(0);
+}
+pub fn main() !void {
+ var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };
+ var b: @Vector(4, u32) = [_]u32{ 5, 6, 7, 8 };
+ const x = sub(b, a);
+ _ = x;
+ return error.TestFailed;
+}
+fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
+ return a - b;
+}
+// run
+// backend=stage1
\ No newline at end of file
test/cases/README.md
@@ -0,0 +1,61 @@
+# Test Case Quick Reference
+
+Use comments at the **end of the file** to indicate metadata about the test
+case. Here are examples of different kinds of tests:
+
+## Compile Error Test
+
+If you want it to be run with `zig test` and match expected error messages:
+
+```zig
+// error
+// is_test=1
+//
+// :4:13: error: 'try' outside function scope
+```
+
+## Execution
+
+This will do `zig run` on the code and expect exit code 0.
+
+```zig
+// run
+```
+
+## Incremental Compilation
+
+Make multiple files that have ".", and then an integer, before the ".zig"
+extension, like this:
+
+```
+hello.0.zig
+hello.1.zig
+hello.2.zig
+```
+
+Each file can be a different kind of test, such as expecting compile errors,
+or expecting to be run and exit(0). The test harness will use these to simulate
+incremental compilation.
+
+At the time of writing there is no way to specify multiple files being changed
+as part of an update.
+
+## Subdirectories
+
+Subdirectories do not have any semantic meaning but they can be used for
+organization since the test harness will recurse into them. The full directory
+path will be prepended as a prefix on the test case name.
+
+## Limiting which Backends and Targets are Tested
+
+```zig
+// run
+// backend=stage2,llvm
+// target=x86_64-linux,x86_64-macos
+```
+
+Possible backends are:
+
+ * `stage1`: equivalent to `-fstage1`.
+ * `stage2`: equivalent to passing `-fno-stage1 -fno-LLVM`.
+ * `llvm`: equivalent to `-fLLVM -fno-stage1`.
test/runtime_safety.zig
@@ -1,1206 +0,0 @@
-const tests = @import("tests.zig");
-
-pub fn addCases(cases: *tests.CompareOutputContext) void {
- {
- const check_panic_msg =
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "reached unreachable code")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- ;
-
- cases.addRuntimeSafety("switch on corrupted enum value",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\const E = enum(u32) {
- \\ X = 1,
- \\};
- \\pub fn main() void {
- \\ var e: E = undefined;
- \\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
- \\ switch (e) {
- \\ .X => @breakpoint(),
- \\ }
- \\}
- );
-
- cases.addRuntimeSafety("switch on corrupted union value",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\const U = union(enum(u32)) {
- \\ X: u8,
- \\};
- \\pub fn main() void {
- \\ var u: U = undefined;
- \\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
- \\ switch (u) {
- \\ .X => @breakpoint(),
- \\ }
- \\}
- );
- }
-
- {
- const check_panic_msg =
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "invalid enum value")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- ;
-
- cases.addRuntimeSafety("@tagName on corrupted enum value",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\const E = enum(u32) {
- \\ X = 1,
- \\};
- \\pub fn main() void {
- \\ var e: E = undefined;
- \\ @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
- \\ var n = @tagName(e);
- \\ _ = n;
- \\}
- );
-
- cases.addRuntimeSafety("@tagName on corrupted union value",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\const U = union(enum(u32)) {
- \\ X: u8,
- \\};
- \\pub fn main() void {
- \\ var u: U = undefined;
- \\ @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
- \\ var t: @typeInfo(U).Union.tag_type.? = u;
- \\ var n = @tagName(t);
- \\ _ = n;
- \\}
- );
- }
-
- {
- const check_panic_msg =
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "index out of bounds")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- ;
-
- cases.addRuntimeSafety("slice with sentinel out of bounds",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\pub fn main() void {
- \\ var buf = [4]u8{'a','b','c',0};
- \\ const input: []u8 = &buf;
- \\ const slice = input[0..4 :0];
- \\ _ = slice;
- \\}
- );
- cases.addRuntimeSafety("empty slice with sentinel out of bounds",
- \\const std = @import("std");
- ++ check_panic_msg ++
- \\pub fn main() void {
- \\ var buf_zero = [0]u8{};
- \\ const input: []u8 = &buf_zero;
- \\ const slice = input[0..0 :0];
- \\ _ = slice;
- \\}
- );
- }
-
- cases.addRuntimeSafety("truncating vector cast",
- \\const std = @import("std");
- \\const V = @import("std").meta.Vector;
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x = @splat(4, @as(u32, 0xdeadbeef));
- \\ var y = @intCast(V(4, u16), x);
- \\ _ = y;
- \\}
- );
-
- cases.addRuntimeSafety("unsigned-signed vector cast",
- \\const std = @import("std");
- \\const V = @import("std").meta.Vector;
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "integer cast truncated bits")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x = @splat(4, @as(u32, 0x80000000));
- \\ var y = @intCast(V(4, i32), x);
- \\ _ = y;
- \\}
- );
-
- cases.addRuntimeSafety("signed-unsigned vector cast",
- \\const std = @import("std");
- \\const V = @import("std").meta.Vector;
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "attempt to cast negative value to unsigned integer")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x = @splat(4, @as(i32, -2147483647));
- \\ var y = @intCast(V(4, u32), x);
- \\ _ = y;
- \\}
- );
-
- cases.addRuntimeSafety("shift left by huge amount",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x: u24 = 42;
- \\ var y: u5 = 24;
- \\ var z = x >> y;
- \\ _ = z;
- \\}
- );
-
- cases.addRuntimeSafety("shift right by huge amount",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x: u24 = 42;
- \\ var y: u5 = 24;
- \\ var z = x << y;
- \\ _ = z;
- \\}
- );
-
- cases.addRuntimeSafety("slice sentinel mismatch - optional pointers",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var buf: [4]?*i32 = undefined;
- \\ const slice = buf[0..3 :null];
- \\ _ = slice;
- \\}
- );
-
- cases.addRuntimeSafety("slice sentinel mismatch - floats",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var buf: [4]f32 = undefined;
- \\ const slice = buf[0..3 :1.2];
- \\ _ = slice;
- \\}
- );
-
- cases.addRuntimeSafety("pointer slice sentinel mismatch",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var buf: [4]u8 = undefined;
- \\ const ptr: [*]u8 = &buf;
- \\ const slice = ptr[0..3 :0];
- \\ _ = slice;
- \\}
- );
-
- cases.addRuntimeSafety("slice slice sentinel mismatch",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var buf: [4]u8 = undefined;
- \\ const slice = buf[0..];
- \\ const slice2 = slice[0..3 :0];
- \\ _ = slice2;
- \\}
- );
-
- cases.addRuntimeSafety("array slice sentinel mismatch",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "sentinel mismatch")) {
- \\ std.process.exit(126); // good
- \\ }
- \\ std.process.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var buf: [4]u8 = undefined;
- \\ const slice = buf[0..3 :0];
- \\ _ = slice;
- \\}
- );
-
- cases.addRuntimeSafety("intToPtr with misaligned address",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "incorrect alignment")) {
- \\ std.os.exit(126); // good
- \\ }
- \\ std.os.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ var x: usize = 5;
- \\ var y = @intToPtr([*]align(4) u8, x);
- \\ _ = y;
- \\}
- );
-
- cases.addRuntimeSafety("resuming a non-suspended function which never been suspended",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\fn foo() void {
- \\ var f = async bar(@frame());
- \\ _ = f;
- \\ std.os.exit(0);
- \\}
- \\
- \\fn bar(frame: anyframe) void {
- \\ suspend {
- \\ resume frame;
- \\ }
- \\ std.os.exit(0);
- \\}
- \\
- \\pub fn main() void {
- \\ _ = async foo();
- \\}
- );
-
- cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\fn foo() void {
- \\ suspend {
- \\ global_frame = @frame();
- \\ }
- \\ var f = async bar(@frame());
- \\ _ = f;
- \\ std.os.exit(0);
- \\}
- \\
- \\fn bar(frame: anyframe) void {
- \\ suspend {
- \\ resume frame;
- \\ }
- \\ std.os.exit(0);
- \\}
- \\
- \\var global_frame: anyframe = undefined;
- \\pub fn main() void {
- \\ _ = async foo();
- \\ resume global_frame;
- \\ std.os.exit(0);
- \\}
- );
-
- cases.addRuntimeSafety("nosuspend function call, callee suspends",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ _ = nosuspend add(101, 100);
- \\}
- \\fn add(a: i32, b: i32) i32 {
- \\ if (a > 100) {
- \\ suspend {}
- \\ }
- \\ return a + b;
- \\}
- );
-
- cases.addRuntimeSafety("awaiting twice",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\var frame: anyframe = undefined;
- \\
- \\pub fn main() void {
- \\ _ = async amain();
- \\ resume frame;
- \\}
- \\
- \\fn amain() void {
- \\ var f = async func();
- \\ await f;
- \\ await f;
- \\}
- \\
- \\fn func() void {
- \\ suspend {
- \\ frame = @frame();
- \\ }
- \\}
- );
-
- cases.addRuntimeSafety("@asyncCall with too small a frame",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var bytes: [1]u8 align(16) = undefined;
- \\ var ptr = other;
- \\ var frame = @asyncCall(&bytes, {}, ptr, .{});
- \\ _ = frame;
- \\}
- \\fn other() callconv(.Async) void {
- \\ suspend {}
- \\}
- );
-
- cases.addRuntimeSafety("resuming a function which is awaiting a frame",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var frame = async first();
- \\ resume frame;
- \\}
- \\fn first() void {
- \\ var frame = async other();
- \\ await frame;
- \\}
- \\fn other() void {
- \\ suspend {}
- \\}
- );
-
- cases.addRuntimeSafety("resuming a function which is awaiting a call",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var frame = async first();
- \\ resume frame;
- \\}
- \\fn first() void {
- \\ other();
- \\}
- \\fn other() void {
- \\ suspend {}
- \\}
- );
-
- cases.addRuntimeSafety("invalid resume of async function",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var p = async suspendOnce();
- \\ resume p; //ok
- \\ resume p; //bad
- \\}
- \\fn suspendOnce() void {
- \\ suspend {}
- \\}
- );
-
- cases.addRuntimeSafety(".? operator on null pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var ptr: ?*i32 = null;
- \\ var b = ptr.?;
- \\ _ = b;
- \\}
- );
-
- cases.addRuntimeSafety(".? operator on C pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var ptr: [*c]i32 = null;
- \\ var b = ptr.?;
- \\ _ = b;
- \\}
- );
-
- cases.addRuntimeSafety("@intToPtr address zero to non-optional pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var zero: usize = 0;
- \\ var b = @intToPtr(*i32, zero);
- \\ _ = b;
- \\}
- );
-
- cases.addRuntimeSafety("@intToPtr address zero to non-optional byte-aligned pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var zero: usize = 0;
- \\ var b = @intToPtr(*u8, zero);
- \\ _ = b;
- \\}
- );
-
- cases.addRuntimeSafety("pointer casting null to non-optional pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var c_ptr: [*c]u8 = 0;
- \\ var zig_ptr: *u8 = c_ptr;
- \\ _ = zig_ptr;
- \\}
- );
-
- cases.addRuntimeSafety("@intToEnum - no matching tag value",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\const Foo = enum {
- \\ A,
- \\ B,
- \\ C,
- \\};
- \\pub fn main() void {
- \\ baz(bar(3));
- \\}
- \\fn bar(a: u2) Foo {
- \\ return @intToEnum(Foo, a);
- \\}
- \\fn baz(_: Foo) void {}
- );
-
- cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ baz(bar(-1.1));
- \\}
- \\fn bar(a: f32) u8 {
- \\ return @floatToInt(u8, a);
- \\}
- \\fn baz(_: u8) void { }
- );
-
- cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ baz(bar(-129.1));
- \\}
- \\fn bar(a: f32) i8 {
- \\ return @floatToInt(i8, a);
- \\}
- \\fn baz(_: i8) void { }
- );
-
- cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ baz(bar(256.2));
- \\}
- \\fn bar(a: f32) u8 {
- \\ return @floatToInt(u8, a);
- \\}
- \\fn baz(_: u8) void { }
- );
-
- cases.addRuntimeSafety("calling panic",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ @panic("oh no");
- \\}
- );
-
- cases.addRuntimeSafety("out of bounds slice access",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ const a = [_]i32{1, 2, 3, 4};
- \\ baz(bar(&a));
- \\}
- \\fn bar(a: []const i32) i32 {
- \\ return a[4];
- \\}
- \\fn baz(_: i32) void { }
- );
-
- cases.addRuntimeSafety("integer addition overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = add(65530, 10);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn add(a: u16, b: u16) u16 {
- \\ return a + b;
- \\}
- );
-
- cases.addRuntimeSafety("vector integer addition overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var a: @Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 };
- \\ var b: @Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
- \\ const x = add(a, b);
- \\ _ = x;
- \\}
- \\fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
- \\ return a + b;
- \\}
- );
-
- cases.addRuntimeSafety("vector integer subtraction overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var a: @Vector(4, u32) = [_]u32{ 1, 2, 8, 4 };
- \\ var b: @Vector(4, u32) = [_]u32{ 5, 6, 7, 8 };
- \\ const x = sub(b, a);
- \\ _ = x;
- \\}
- \\fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
- \\ return a - b;
- \\}
- );
-
- cases.addRuntimeSafety("vector integer multiplication overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var a: @Vector(4, u8) = [_]u8{ 1, 2, 200, 4 };
- \\ var b: @Vector(4, u8) = [_]u8{ 5, 6, 2, 8 };
- \\ const x = mul(b, a);
- \\ _ = x;
- \\}
- \\fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
- \\ return a * b;
- \\}
- );
-
- cases.addRuntimeSafety("vector integer negation overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var a: @Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 };
- \\ const x = neg(a);
- \\ _ = x;
- \\}
- \\fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
- \\ return -a;
- \\}
- );
-
- cases.addRuntimeSafety("integer subtraction overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = sub(10, 20);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn sub(a: u16, b: u16) u16 {
- \\ return a - b;
- \\}
- );
-
- cases.addRuntimeSafety("integer multiplication overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = mul(300, 6000);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn mul(a: u16, b: u16) u16 {
- \\ return a * b;
- \\}
- );
-
- cases.addRuntimeSafety("integer negation overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = neg(-32768);
- \\ if (x == 32767) return error.Whatever;
- \\}
- \\fn neg(a: i16) i16 {
- \\ return -a;
- \\}
- );
-
- cases.addRuntimeSafety("signed integer division overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = div(-32768, -1);
- \\ if (x == 32767) return error.Whatever;
- \\}
- \\fn div(a: i16, b: i16) i16 {
- \\ return @divTrunc(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("signed integer division overflow - vectors",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ var a: @Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 };
- \\ var b: @Vector(4, i16) = [_]i16{ 1, 2, -1, 4 };
- \\ const x = div(a, b);
- \\ if (x[2] == 32767) return error.Whatever;
- \\}
- \\fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
- \\ return @divTrunc(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("signed shift left overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shl(-16385, 1);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shl(a: i16, b: u4) i16 {
- \\ return @shlExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("unsigned shift left overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shl(0b0010111111111111, 3);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shl(a: u16, b: u4) u16 {
- \\ return @shlExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("signed shift right overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shr(-16385, 1);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shr(a: i16, b: u4) i16 {
- \\ return @shrExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("unsigned shift right overflow",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shr(0b0010111111111111, 3);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shr(a: u16, b: u4) u16 {
- \\ return @shrExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("integer division by zero",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ const x = div0(999, 0);
- \\ _ = x;
- \\}
- \\fn div0(a: i32, b: i32) i32 {
- \\ return @divTrunc(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("integer division by zero - vectors",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
- \\ var b: @Vector(4, i32) = [4]i32{111, 0, 333, 444};
- \\ const x = div0(a, b);
- \\ _ = x;
- \\}
- \\fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
- \\ return @divTrunc(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("exact division failure",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = divExact(10, 3);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn divExact(a: i32, b: i32) i32 {
- \\ return @divExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("exact division failure - vectors",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ var a: @Vector(4, i32) = [4]i32{111, 222, 333, 444};
- \\ var b: @Vector(4, i32) = [4]i32{111, 222, 333, 441};
- \\ const x = divExact(a, b);
- \\ _ = x;
- \\}
- \\fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
- \\ return @divExact(a, b);
- \\}
- );
-
- cases.addRuntimeSafety("cast []u8 to bigger slice of wrong size",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = widenSlice(&[_]u8{1, 2, 3, 4, 5});
- \\ if (x.len == 0) return error.Whatever;
- \\}
- \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
- \\ return std.mem.bytesAsSlice(i32, slice);
- \\}
- );
-
- cases.addRuntimeSafety("value does not fit in shortening cast",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shorten_cast(200);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shorten_cast(x: i32) i8 {
- \\ return @intCast(i8, x);
- \\}
- );
-
- cases.addRuntimeSafety("value does not fit in shortening cast - u0",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = shorten_cast(1);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn shorten_cast(x: u8) u0 {
- \\ return @intCast(u0, x);
- \\}
- );
-
- cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ const x = unsigned_cast(-10);
- \\ if (x == 0) return error.Whatever;
- \\}
- \\fn unsigned_cast(x: i32) u32 {
- \\ return @intCast(u32, x);
- \\}
- );
-
- cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var value: c_short = -1;
- \\ var casted = @intCast(u32, value);
- \\ _ = casted;
- \\}
- );
-
- cases.addRuntimeSafety("unsigned integer not fitting in cast to signed integer - same bit count",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ var value: u8 = 245;
- \\ var casted = @intCast(i8, value);
- \\ _ = casted;
- \\}
- );
-
- cases.addRuntimeSafety("unwrap error",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = stack_trace;
- \\ if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
- \\ std.os.exit(126); // good
- \\ }
- \\ std.os.exit(0); // test failed
- \\}
- \\pub fn main() void {
- \\ bar() catch unreachable;
- \\}
- \\fn bar() !void {
- \\ return error.Whatever;
- \\}
- );
-
- cases.addRuntimeSafety("cast integer to global error and no code matches",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() void {
- \\ bar(9999) catch {};
- \\}
- \\fn bar(x: u16) anyerror {
- \\ return @intToError(x);
- \\}
- );
-
- cases.addRuntimeSafety("@errSetCast error not present in destination",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\const Set1 = error{A, B};
- \\const Set2 = error{A, C};
- \\pub fn main() void {
- \\ foo(Set1.B) catch {};
- \\}
- \\fn foo(set1: Set1) Set2 {
- \\ return @errSetCast(Set2, set1);
- \\}
- );
-
- cases.addRuntimeSafety("@alignCast misaligned",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\pub fn main() !void {
- \\ var array align(4) = [_]u32{0x11111111, 0x11111111};
- \\ const bytes = std.mem.sliceAsBytes(array[0..]);
- \\ if (foo(bytes) != 0x11111111) return error.Wrong;
- \\}
- \\fn foo(bytes: []u8) u32 {
- \\ const slice4 = bytes[1..5];
- \\ const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4));
- \\ return int_slice[0];
- \\}
- );
-
- cases.addRuntimeSafety("bad union field access",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\
- \\const Foo = union {
- \\ float: f32,
- \\ int: u32,
- \\};
- \\
- \\pub fn main() void {
- \\ var f = Foo { .int = 42 };
- \\ bar(&f);
- \\}
- \\
- \\fn bar(f: *Foo) void {
- \\ f.float = 12.34;
- \\}
- );
-
- // @intCast a runtime integer to u0 actually results in a comptime-known value,
- // but we still emit a safety check to ensure the integer was 0 and thus
- // did not truncate information.
- cases.addRuntimeSafety("@intCast to u0",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\
- \\pub fn main() void {
- \\ bar(1, 1);
- \\}
- \\
- \\fn bar(one: u1, not_zero: i32) void {
- \\ var x = one << @intCast(u0, not_zero);
- \\ _ = x;
- \\}
- );
-
- // This case makes sure that the code compiles and runs. There is not actually a special
- // runtime safety check having to do specifically with error return traces across suspend points.
- cases.addRuntimeSafety("error return trace across suspend points",
- \\const std = @import("std");
- \\
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\
- \\var failing_frame: @Frame(failing) = undefined;
- \\
- \\pub fn main() void {
- \\ const p = nonFailing();
- \\ resume p;
- \\ const p2 = async printTrace(p);
- \\ _ = p2;
- \\}
- \\
- \\fn nonFailing() anyframe->anyerror!void {
- \\ failing_frame = async failing();
- \\ return &failing_frame;
- \\}
- \\
- \\fn failing() anyerror!void {
- \\ suspend {}
- \\ return second();
- \\}
- \\
- \\fn second() callconv(.Async) anyerror!void {
- \\ return error.Fail;
- \\}
- \\
- \\fn printTrace(p: anyframe->anyerror!void) void {
- \\ (await p) catch unreachable;
- \\}
- );
-
- // Slicing a C pointer returns a non-allowzero slice, thus we need to emit
- // a safety check to ensure the pointer is not null.
- cases.addRuntimeSafety("slicing null C pointer",
- \\const std = @import("std");
- \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
- \\ _ = message;
- \\ _ = stack_trace;
- \\ std.os.exit(126);
- \\}
- \\
- \\pub fn main() void {
- \\ var ptr: [*c]const u32 = null;
- \\ var slice = ptr[0..3];
- \\ _ = slice;
- \\}
- );
-}
test/tests.zig
@@ -18,7 +18,6 @@ const compare_output = @import("compare_output.zig");
const standalone = @import("standalone.zig");
const stack_traces = @import("stack_traces.zig");
const assemble_and_link = @import("assemble_and_link.zig");
-const runtime_safety = @import("runtime_safety.zig");
const translate_c = @import("translate_c.zig");
const run_translated_c = @import("run_translated_c.zig");
const gen_h = @import("gen_h.zig");
@@ -455,21 +454,6 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []
return cases.step;
}
-pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompareOutputContext) catch unreachable;
- cases.* = CompareOutputContext{
- .b = b,
- .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
- .test_index = 0,
- .test_filter = test_filter,
- .modes = modes,
- };
-
- runtime_safety.addCases(cases);
-
- return cases.step;
-}
-
pub fn addStandaloneTests(
b: *build.Builder,
test_filter: ?[]const u8,
build.zig
@@ -40,10 +40,10 @@ pub fn build(b: *Builder) !void {
const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
- var test_stage2 = b.addTest("src/test.zig");
- test_stage2.setBuildMode(mode);
- test_stage2.addPackagePath("test_cases", "test/cases.zig");
- test_stage2.single_threaded = single_threaded;
+ var test_cases = b.addTest("src/test.zig");
+ test_cases.setBuildMode(mode);
+ test_cases.addPackagePath("test_cases", "test/cases.zig");
+ test_cases.single_threaded = single_threaded;
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
@@ -158,7 +158,7 @@ pub fn build(b: *Builder) !void {
if (target.isWindows() and target.getAbi() == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
- test_stage2.want_lto = false;
+ test_cases.want_lto = false;
}
const exe_options = b.addOptions();
@@ -175,7 +175,7 @@ pub fn build(b: *Builder) !void {
if (link_libc) {
exe.linkLibC();
- test_stage2.linkLibC();
+ test_cases.linkLibC();
}
const is_debug = mode == .Debug;
@@ -258,7 +258,7 @@ pub fn build(b: *Builder) !void {
zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
- for ([_]*std.build.LibExeObjStep{ zig0, exe, test_stage2 }) |artifact| {
+ for ([_]*std.build.LibExeObjStep{ zig0, exe, test_cases }) |artifact| {
artifact.addIncludePath("src");
artifact.addIncludePath("deps/SoftFloat-3e/source/include");
artifact.addIncludePath("deps/SoftFloat-3e-prebuilt");
@@ -335,11 +335,11 @@ pub fn build(b: *Builder) !void {
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
- try addCmakeCfgOptionsToExe(b, cfg, test_stage2, use_zig_libcxx);
+ try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
- try addStaticLlvmOptionsToExe(test_stage2);
+ try addStaticLlvmOptionsToExe(test_cases);
}
}
@@ -381,7 +381,7 @@ pub fn build(b: *Builder) !void {
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
const test_stage2_options = b.addOptions();
- test_stage2.addOptions("build_options", test_stage2_options);
+ test_cases.addOptions("build_options", test_stage2_options);
test_stage2_options.addOption(bool, "enable_logging", enable_logging);
test_stage2_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
@@ -404,10 +404,10 @@ pub fn build(b: *Builder) !void {
test_stage2_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
test_stage2_options.addOption(std.SemanticVersion, "semver", semver);
- const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
- test_stage2_step.dependOn(&test_stage2.step);
+ const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
+ test_cases_step.dependOn(&test_cases.step);
if (!skip_stage2_tests) {
- toolchain_step.dependOn(test_stage2_step);
+ toolchain_step.dependOn(test_cases_step);
}
var chosen_modes: [4]builtin.Mode = undefined;
@@ -485,7 +485,6 @@ pub fn build(b: *Builder) !void {
toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
- toolchain_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
if (!skip_run_translated_c) {
toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));