I am reading the documentation and it says:
Most Illegal Behavior is safety-checked. However, to facilitate optimizations, safety checks are disabled by default in the ReleaseFast and ReleaseSmall optimization modes.
Why does it say most here? Is there any illegal behavior that is never safety checked? Even in debug/releaseSafe builds? Is this just because the @setRuntimeSafety macro and inline assembly can result in unchecked illegal behavior? I’m assuming all of the illegal behavior listed in the Illegal behavior section is safety checked in debug and releaseSafe builds?
Thanks
.
Yes, there is plenty, that range from: solved but not yet implemented, don’t yet have a solution that fits zig, known solution is difficult and slow, or not adequate, to never been solved before ever.
First that comes to mind is pointer casts, they only have 2 checks: alignment (via a separate cast) and size (only applied with slices).
Any cast to/from a type without a defined layout is illegal because you don’t know what data is where.
Well It’s using it after that is the illegal part, and you can go around that by casting back to the correct type. That allows for runtime interfaces to be legal.
There are plans to add unique values into types that don’t have a defined layout that can then be checked when casting, and ofc zig will provide a way around that as it could get in the way of some legal things.
Another pointer related IB that comes to mind is incorrect use of @constCast; if the pointer points to memory that is supposed to be const, and you write to it, that is unchecked illegal behaviour.
1 Like
Searching the language reference for “unchecked” reveals an example.
var declarations inside functions are stored in the function’s stack frame. Once a function returns, any Pointers to variables in the function’s stack frame become invalid references, and dereferencing them becomes unchecked Illegal Behavior.
Here is a demonstration:
fn obfuscate(arg: *u8) *u8 {
return arg;
}
fn buggyFn(x: u8) *u8 {
var stack_allocated: u8 = x;
return obfuscate(&stack_allocated);
}
test "fails because of unchecked IB" {
const ptr: *u8 = buggyFn('a');
std.debug.print("mess up the stack\n", .{});
try std.testing.expectEqual('a', ptr.*);
}
2 Likes
Thanks guys, in hindsight these are all obvious examples of unchecked behavior lol.
2 Likes