diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-05-13 00:00:20 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-05-13 14:03:20 -0700 |
| commit | 66f3efb63b4b352b1dbbaa4216fb3b0dabac3f3e (patch) | |
| tree | 5a5613dc1f64234b122883ae518ce970e5da8cec /test | |
| parent | f32928c50dabde1dee40b7137beef0fe72e89b49 (diff) | |
| download | zig-66f3efb63b4b352b1dbbaa4216fb3b0dabac3f3e.tar.gz zig-66f3efb63b4b352b1dbbaa4216fb3b0dabac3f3e.zip | |
migrate runtime safety tests to the new test harness
* migrate runtime safety tests to the new test harness
- this required adding compare output / execution support for stage1
to the test harness.
* rename `zig build test-stage2` to `zig build test-cases` since it now
does quite a bit of stage1 testing actually. I named it this way
since the main directory in the source tree associated with these
tests is "test/cases/".
* add some documentation for the test manifest format.
Diffstat (limited to 'test')
71 files changed, 1378 insertions, 1222 deletions
diff --git a/test/cases/README.md b/test/cases/README.md new file mode 100644 index 0000000000..4c9f401ab6 --- /dev/null +++ b/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`. diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig new file mode 100644 index 0000000000..3948cea443 --- /dev/null +++ b/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 diff --git a/test/cases/safety/@asyncCall with too small a frame.zig b/test/cases/safety/@asyncCall with too small a frame.zig new file mode 100644 index 0000000000..8ae4d4ee3f --- /dev/null +++ b/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 diff --git a/test/cases/safety/@errSetCast error not present in destination.zig b/test/cases/safety/@errSetCast error not present in destination.zig new file mode 100644 index 0000000000..3934307e9e --- /dev/null +++ b/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 diff --git a/test/cases/safety/@floatToInt cannot fit - negative out of range.zig b/test/cases/safety/@floatToInt cannot fit - negative out of range.zig new file mode 100644 index 0000000000..1e7016830e --- /dev/null +++ b/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 diff --git a/test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig b/test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig new file mode 100644 index 0000000000..fbcc7fc11d --- /dev/null +++ b/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 diff --git a/test/cases/safety/@floatToInt cannot fit - positive out of range.zig b/test/cases/safety/@floatToInt cannot fit - positive out of range.zig new file mode 100644 index 0000000000..1ab83edafa --- /dev/null +++ b/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 diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig new file mode 100644 index 0000000000..10c3d22213 --- /dev/null +++ b/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 diff --git a/test/cases/safety/@intToEnum - no matching tag value.zig b/test/cases/safety/@intToEnum - no matching tag value.zig new file mode 100644 index 0000000000..7f66dc050d --- /dev/null +++ b/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 diff --git a/test/cases/safety/@intToPtr address zero to non-optional byte-aligned pointer.zig b/test/cases/safety/@intToPtr address zero to non-optional byte-aligned pointer.zig new file mode 100644 index 0000000000..6c44505af9 --- /dev/null +++ b/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 diff --git a/test/cases/safety/@intToPtr address zero to non-optional pointer.zig b/test/cases/safety/@intToPtr address zero to non-optional pointer.zig new file mode 100644 index 0000000000..9f61766884 --- /dev/null +++ b/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 diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig new file mode 100644 index 0000000000..577ba183d5 --- /dev/null +++ b/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 diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig new file mode 100644 index 0000000000..6012e86833 --- /dev/null +++ b/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 diff --git a/test/cases/safety/array slice sentinel mismatch.zig b/test/cases/safety/array slice sentinel mismatch.zig new file mode 100644 index 0000000000..83e8b1f787 --- /dev/null +++ b/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 + diff --git a/test/cases/safety/awaiting twice.zig b/test/cases/safety/awaiting twice.zig new file mode 100644 index 0000000000..2a64320c07 --- /dev/null +++ b/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 diff --git a/test/cases/safety/bad union field access.zig b/test/cases/safety/bad union field access.zig new file mode 100644 index 0000000000..cc476f57c5 --- /dev/null +++ b/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 diff --git a/test/cases/safety/calling panic.zig b/test/cases/safety/calling panic.zig new file mode 100644 index 0000000000..e6ff577e7f --- /dev/null +++ b/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 diff --git a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig new file mode 100644 index 0000000000..5bdee09e52 --- /dev/null +++ b/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 diff --git a/test/cases/safety/cast integer to global error and no code matches.zig b/test/cases/safety/cast integer to global error and no code matches.zig new file mode 100644 index 0000000000..57b72aab5d --- /dev/null +++ b/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 diff --git a/test/cases/safety/empty slice with sentinel out of bounds.zig b/test/cases/safety/empty slice with sentinel out of bounds.zig new file mode 100644 index 0000000000..2ea22ed41d --- /dev/null +++ b/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 diff --git a/test/cases/safety/error return trace across suspend points.zig b/test/cases/safety/error return trace across suspend points.zig new file mode 100644 index 0000000000..b27bc770fb --- /dev/null +++ b/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 diff --git a/test/cases/safety/exact division failure - vectors.zig b/test/cases/safety/exact division failure - vectors.zig new file mode 100644 index 0000000000..77dd427683 --- /dev/null +++ b/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 diff --git a/test/cases/safety/exact division failure.zig b/test/cases/safety/exact division failure.zig new file mode 100644 index 0000000000..c363df94ab --- /dev/null +++ b/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 diff --git a/test/cases/safety/intToPtr with misaligned address.zig b/test/cases/safety/intToPtr with misaligned address.zig new file mode 100644 index 0000000000..eaca2cb32d --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer addition overflow.zig b/test/cases/safety/integer addition overflow.zig new file mode 100644 index 0000000000..74fce53890 --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer division by zero - vectors.zig b/test/cases/safety/integer division by zero - vectors.zig new file mode 100644 index 0000000000..b3365bfcae --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer division by zero.zig b/test/cases/safety/integer division by zero.zig new file mode 100644 index 0000000000..b209a69d35 --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer multiplication overflow.zig b/test/cases/safety/integer multiplication overflow.zig new file mode 100644 index 0000000000..0eb68fabe0 --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer negation overflow.zig b/test/cases/safety/integer negation overflow.zig new file mode 100644 index 0000000000..c9d7e4f919 --- /dev/null +++ b/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 diff --git a/test/cases/safety/integer subtraction overflow.zig b/test/cases/safety/integer subtraction overflow.zig new file mode 100644 index 0000000000..f1b17020a8 --- /dev/null +++ b/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 diff --git a/test/cases/safety/invalid resume of async function.zig b/test/cases/safety/invalid resume of async function.zig new file mode 100644 index 0000000000..acde5eed92 --- /dev/null +++ b/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 diff --git a/test/cases/safety/nosuspend function call, callee suspends.zig b/test/cases/safety/nosuspend function call, callee suspends.zig new file mode 100644 index 0000000000..fc99174bd0 --- /dev/null +++ b/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 diff --git a/test/cases/safety/optional unwrap operator on C pointer.zig b/test/cases/safety/optional unwrap operator on C pointer.zig new file mode 100644 index 0000000000..4d5fa54d3d --- /dev/null +++ b/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 diff --git a/test/cases/safety/optional unwrap operator on null pointer.zig b/test/cases/safety/optional unwrap operator on null pointer.zig new file mode 100644 index 0000000000..eb791be268 --- /dev/null +++ b/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 diff --git a/test/cases/safety/out of bounds slice access.zig b/test/cases/safety/out of bounds slice access.zig new file mode 100644 index 0000000000..e429328b1e --- /dev/null +++ b/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 diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig new file mode 100644 index 0000000000..a61ba2fa9b --- /dev/null +++ b/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 diff --git a/test/cases/safety/pointer slice sentinel mismatch.zig b/test/cases/safety/pointer slice sentinel mismatch.zig new file mode 100644 index 0000000000..f796534783 --- /dev/null +++ b/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 diff --git a/test/cases/safety/resuming a function which is awaiting a call.zig b/test/cases/safety/resuming a function which is awaiting a call.zig new file mode 100644 index 0000000000..63c4e1ef50 --- /dev/null +++ b/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 diff --git a/test/cases/safety/resuming a function which is awaiting a frame.zig b/test/cases/safety/resuming a function which is awaiting a frame.zig new file mode 100644 index 0000000000..0f68be4db8 --- /dev/null +++ b/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 diff --git a/test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig b/test/cases/safety/resuming a non-suspended function which has been suspended and resumed.zig new file mode 100644 index 0000000000..3f3a62fe4e --- /dev/null +++ b/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 diff --git a/test/cases/safety/resuming a non-suspended function which never been suspended.zig b/test/cases/safety/resuming a non-suspended function which never been suspended.zig new file mode 100644 index 0000000000..b0dfbc1911 --- /dev/null +++ b/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 diff --git a/test/cases/safety/shift left by huge amount.zig b/test/cases/safety/shift left by huge amount.zig new file mode 100644 index 0000000000..8cf5ec3752 --- /dev/null +++ b/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 diff --git a/test/cases/safety/shift right by huge amount.zig b/test/cases/safety/shift right by huge amount.zig new file mode 100644 index 0000000000..90a620ddc4 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed integer division overflow - vectors.zig b/test/cases/safety/signed integer division overflow - vectors.zig new file mode 100644 index 0000000000..5ce8fd740e --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed integer division overflow.zig b/test/cases/safety/signed integer division overflow.zig new file mode 100644 index 0000000000..64e1827b45 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig new file mode 100644 index 0000000000..7c08fcddb2 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig new file mode 100644 index 0000000000..6ed4246403 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed shift left overflow.zig b/test/cases/safety/signed shift left overflow.zig new file mode 100644 index 0000000000..814d52b1a9 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed shift right overflow.zig b/test/cases/safety/signed shift right overflow.zig new file mode 100644 index 0000000000..fc2e00cee3 --- /dev/null +++ b/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 diff --git a/test/cases/safety/signed-unsigned vector cast.zig b/test/cases/safety/signed-unsigned vector cast.zig new file mode 100644 index 0000000000..4de78e969d --- /dev/null +++ b/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 diff --git a/test/cases/safety/slice sentinel mismatch - floats.zig b/test/cases/safety/slice sentinel mismatch - floats.zig new file mode 100644 index 0000000000..df5edc1fdf --- /dev/null +++ b/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 diff --git a/test/cases/safety/slice sentinel mismatch - optional pointers.zig b/test/cases/safety/slice sentinel mismatch - optional pointers.zig new file mode 100644 index 0000000000..8199f3280e --- /dev/null +++ b/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 diff --git a/test/cases/safety/slice slice sentinel mismatch.zig b/test/cases/safety/slice slice sentinel mismatch.zig new file mode 100644 index 0000000000..8303b1a288 --- /dev/null +++ b/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 diff --git a/test/cases/safety/slice with sentinel out of bounds.zig b/test/cases/safety/slice with sentinel out of bounds.zig new file mode 100644 index 0000000000..7fc890e144 --- /dev/null +++ b/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 diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig new file mode 100644 index 0000000000..2b678ad9cf --- /dev/null +++ b/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 diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig new file mode 100644 index 0000000000..b574444341 --- /dev/null +++ b/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 diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig new file mode 100644 index 0000000000..8ec4fece1b --- /dev/null +++ b/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 diff --git a/test/cases/safety/truncating vector cast.zig b/test/cases/safety/truncating vector cast.zig new file mode 100644 index 0000000000..f2795d9c66 --- /dev/null +++ b/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 diff --git a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig new file mode 100644 index 0000000000..6118d5a5ea --- /dev/null +++ b/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 diff --git a/test/cases/safety/unsigned shift left overflow.zig b/test/cases/safety/unsigned shift left overflow.zig new file mode 100644 index 0000000000..3fa2658c3f --- /dev/null +++ b/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 diff --git a/test/cases/safety/unsigned shift right overflow.zig b/test/cases/safety/unsigned shift right overflow.zig new file mode 100644 index 0000000000..0953229a67 --- /dev/null +++ b/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 diff --git a/test/cases/safety/unsigned-signed vector cast.zig b/test/cases/safety/unsigned-signed vector cast.zig new file mode 100644 index 0000000000..9c157d8f40 --- /dev/null +++ b/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 diff --git a/test/cases/safety/unwrap error.zig b/test/cases/safety/unwrap error.zig new file mode 100644 index 0000000000..451b9b3891 --- /dev/null +++ b/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 diff --git a/test/cases/safety/value does not fit in shortening cast - u0.zig b/test/cases/safety/value does not fit in shortening cast - u0.zig new file mode 100644 index 0000000000..3bbcaf972f --- /dev/null +++ b/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 diff --git a/test/cases/safety/value does not fit in shortening cast.zig b/test/cases/safety/value does not fit in shortening cast.zig new file mode 100644 index 0000000000..2c7409d225 --- /dev/null +++ b/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 diff --git a/test/cases/safety/vector integer addition overflow.zig b/test/cases/safety/vector integer addition overflow.zig new file mode 100644 index 0000000000..32b045cd56 --- /dev/null +++ b/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 diff --git a/test/cases/safety/vector integer multiplication overflow.zig b/test/cases/safety/vector integer multiplication overflow.zig new file mode 100644 index 0000000000..2c9d48e1fd --- /dev/null +++ b/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 diff --git a/test/cases/safety/vector integer negation overflow.zig b/test/cases/safety/vector integer negation overflow.zig new file mode 100644 index 0000000000..81506da41c --- /dev/null +++ b/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 diff --git a/test/cases/safety/vector integer subtraction overflow.zig b/test/cases/safety/vector integer subtraction overflow.zig new file mode 100644 index 0000000000..c3a21e971c --- /dev/null +++ b/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 diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig deleted file mode 100644 index f73226159a..0000000000 --- a/test/runtime_safety.zig +++ /dev/null @@ -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; - \\} - ); -} diff --git a/test/tests.zig b/test/tests.zig index 62c437e7f7..e44b190bb4 100644 --- a/test/tests.zig +++ b/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, |
