const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { { const check_panic_msg = \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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: ?*@import("builtin").StackTrace) noreturn { \\ 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); \\} ); 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); \\} ); } { const check_panic_msg = \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ if (std.mem.eql(u8, message, "index out of bounds")) { \\ std.process.exit(126); // good \\ } \\ std.process.exit(0); // test failed \\} ; cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf = [4]u8{'a','b','c',0}; \\ const slice = buf[0..4 :0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf = [4]u8{'a','b','c',0}; \\ const slice = buf[0..:0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf_zero = [0]u8{}; \\ const slice = buf_zero[0..0 :0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf_zero = [0]u8{}; \\ const slice = buf_zero[0..:0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf_sentinel = [2:0]u8{'a','b'}; \\ @ptrCast(*[3]u8, &buf_sentinel)[2] = 0; \\ const slice = buf_sentinel[0..3 :0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 }; \\ const slice = buf_slice[0..3 :0]; \\} ); cases.addRuntimeSafety("slicing operator with sentinel", \\const std = @import("std"); ++ check_panic_msg ++ \\pub fn main() void { \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 }; \\ const slice = buf_slice[0.. :0]; \\} ); } cases.addRuntimeSafety("truncating vector cast", \\const std = @import("std"); \\const V = @import("std").meta.Vector; \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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); \\} ); cases.addRuntimeSafety("unsigned-signed vector cast", \\const std = @import("std"); \\const V = @import("std").meta.Vector; \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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); \\} ); cases.addRuntimeSafety("signed-unsigned vector cast", \\const std = @import("std"); \\const V = @import("std").meta.Vector; \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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); \\} ); cases.addRuntimeSafety("shift left by huge amount", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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; \\} ); cases.addRuntimeSafety("shift right by huge amount", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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; \\} ); cases.addRuntimeSafety("slice sentinel mismatch - optional pointers", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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]; \\} ); cases.addRuntimeSafety("slice sentinel mismatch - floats", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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]; \\} ); cases.addRuntimeSafety("pointer slice sentinel mismatch", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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]; \\} ); cases.addRuntimeSafety("slice slice sentinel mismatch", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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]; \\} ); cases.addRuntimeSafety("array slice sentinel mismatch", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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]; \\} ); cases.addRuntimeSafety("intToPtr with misaligned address", \\const std = @import("std"); \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ 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); \\} ); cases.addRuntimeSafety("resuming a non-suspended function which never been suspended", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\fn foo() void { \\ var f = async bar(@frame()); \\ @import("std").os.exit(0); \\} \\ \\fn bar(frame: anyframe) void { \\ suspend { \\ resume frame; \\ } \\ @import("std").os.exit(0); \\} \\ \\pub fn main() void { \\ _ = async foo(); \\} ); cases.addRuntimeSafety("resuming a non-suspended function which has been suspended and resumed", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\fn foo() void { \\ suspend { \\ global_frame = @frame(); \\ } \\ var f = async bar(@frame()); \\ @import("std").os.exit(0); \\} \\ \\fn bar(frame: anyframe) void { \\ suspend { \\ resume frame; \\ } \\ @import("std").os.exit(0); \\} \\ \\var global_frame: anyframe = undefined; \\pub fn main() void { \\ _ = async foo(); \\ resume global_frame; \\ @import("std").os.exit(0); \\} ); cases.addRuntimeSafety("nosuspend function call, callee suspends", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var bytes: [1]u8 align(16) = undefined; \\ var ptr = other; \\ var frame = @asyncCall(&bytes, {}, ptr, .{}); \\} \\fn other() callconv(.Async) void { \\ suspend; \\} ); cases.addRuntimeSafety("resuming a function which is awaiting a frame", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var ptr: ?*i32 = null; \\ var b = ptr.?; \\} ); cases.addRuntimeSafety(".? operator on C pointer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var ptr: [*c]i32 = null; \\ var b = ptr.?; \\} ); cases.addRuntimeSafety("@intToPtr address zero to non-optional pointer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var zero: usize = 0; \\ var b = @intToPtr(*i32, zero); \\} ); cases.addRuntimeSafety("@intToPtr address zero to non-optional byte-aligned pointer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var zero: usize = 0; \\ var b = @intToPtr(*u8, zero); \\} ); cases.addRuntimeSafety("pointer casting null to non-optional pointer", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var c_ptr: [*c]u8 = 0; \\ var zig_ptr: *u8 = c_ptr; \\} ); cases.addRuntimeSafety("@intToEnum - no matching tag value", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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(a: Foo) void {} ); cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ baz(bar(-1.1)); \\} \\fn bar(a: f32) u8 { \\ return @floatToInt(u8, a); \\} \\fn baz(a: u8) void { } ); cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ baz(bar(-129.1)); \\} \\fn bar(a: f32) i8 { \\ return @floatToInt(i8, a); \\} \\fn baz(a: i8) void { } ); cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ baz(bar(256.2)); \\} \\fn bar(a: f32) u8 { \\ return @floatToInt(u8, a); \\} \\fn baz(a: u8) void { } ); cases.addRuntimeSafety("calling panic", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ @panic("oh no"); \\} ); cases.addRuntimeSafety("out of bounds slice access", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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(a: i32) void { } ); cases.addRuntimeSafety("integer addition overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var a: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 2, 2147483643, 4 }; \\ var b: @import("std").meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; \\ const x = add(a, b); \\} \\fn add(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.Vector(4, i32) { \\ return a + b; \\} ); cases.addRuntimeSafety("vector integer subtraction overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var a: @import("std").meta.Vector(4, u32) = [_]u32{ 1, 2, 8, 4 }; \\ var b: @import("std").meta.Vector(4, u32) = [_]u32{ 5, 6, 7, 8 }; \\ const x = sub(b, a); \\} \\fn sub(a: @import("std").meta.Vector(4, u32), b: @import("std").meta.Vector(4, u32)) @import("std").meta.Vector(4, u32) { \\ return a - b; \\} ); cases.addRuntimeSafety("vector integer multiplication overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var a: @import("std").meta.Vector(4, u8) = [_]u8{ 1, 2, 200, 4 }; \\ var b: @import("std").meta.Vector(4, u8) = [_]u8{ 5, 6, 2, 8 }; \\ const x = mul(b, a); \\} \\fn mul(a: @import("std").meta.Vector(4, u8), b: @import("std").meta.Vector(4, u8)) @import("std").meta.Vector(4, u8) { \\ return a * b; \\} ); cases.addRuntimeSafety("vector integer negation overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var a: @import("std").meta.Vector(4, i16) = [_]i16{ 1, -32768, 200, 4 }; \\ const x = neg(a); \\} \\fn neg(a: @import("std").meta.Vector(4, i16)) @import("std").meta.Vector(4, i16) { \\ return -a; \\} ); cases.addRuntimeSafety("integer subtraction overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() !void { \\ var a: @import("std").meta.Vector(4, i16) = [_]i16{ 1, 2, -32768, 4 }; \\ var b: @import("std").meta.Vector(4, i16) = [_]i16{ 1, 2, -1, 4 }; \\ const x = div(a, b); \\ if (x[2] == 32767) return error.Whatever; \\} \\fn div(a: @import("std").meta.Vector(4, i16), b: @import("std").meta.Vector(4, i16)) @import("std").meta.Vector(4, i16) { \\ return @divTrunc(a, b); \\} ); cases.addRuntimeSafety("signed shift left overflow", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ const x = div0(999, 0); \\} \\fn div0(a: i32, b: i32) i32 { \\ return @divTrunc(a, b); \\} ); cases.addRuntimeSafety("integer division by zero - vectors", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var a: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; \\ var b: @import("std").meta.Vector(4, i32) = [4]i32{111, 0, 333, 444}; \\ const x = div0(a, b); \\} \\fn div0(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.Vector(4, i32) { \\ return @divTrunc(a, b); \\} ); cases.addRuntimeSafety("exact division failure", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() !void { \\ var a: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 444}; \\ var b: @import("std").meta.Vector(4, i32) = [4]i32{111, 222, 333, 441}; \\ const x = divExact(a, b); \\} \\fn divExact(a: @import("std").meta.Vector(4, i32), b: @import("std").meta.Vector(4, i32)) @import("std").meta.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 { \\ 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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var value: c_short = -1; \\ var casted = @intCast(u32, value); \\} ); cases.addRuntimeSafety("unsigned integer not fitting in cast to signed integer - same bit count", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() void { \\ var value: u8 = 245; \\ var casted = @intCast(i8, value); \\} ); cases.addRuntimeSafety("unwrap error", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { \\ @import("std").os.exit(126); // good \\ } \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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 { \\ 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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("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); \\} ); // 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: ?*@import("builtin").StackTrace) noreturn { \\ std.os.exit(126); \\} \\ \\var failing_frame: @Frame(failing) = undefined; \\ \\pub fn main() void { \\ const p = nonFailing(); \\ resume p; \\ const p2 = async printTrace(p); \\} \\ \\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", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); \\} \\ \\pub fn main() void { \\ var ptr: [*c]const u32 = null; \\ var slice = ptr[0..3]; \\} ); }