There’s a couple of factors at play here. The first is that sizeWin may be stack allocated here, so might not end up in read only memory. The second is that it doesn’t look like Zig’s linker is placing constants in read-only memory.
With LLVM (-OReleaseSmall), the following faults for me:
pub fn main() !void {
const sizeWin: std.posix.winsize = undefined;
const ret = std.c.ioctl(std.posix.STDOUT_FILENO, std.posix.T.IOCGWINSZ, &sizeWin);
std.log.info("return: {}", .{ret});
std.log.info("error: {}", .{std.posix.errno(ret)});
}
Output
info: return: -1
info: error: .FAULT
Presumably LLVM sees that the constant is compile-time known, and places it in .rodata, whereas Zig’s native backend doesn’t (even if I make sizeWin global).
If I force sizeWin to be stack allocated, then it succeeds again:
pub fn main() !void {
var stack_allocated: std.posix.winsize = undefined;
_ = &stack_allocated;
const sizeWin: std.posix.winsize = stack_allocated;
const ret = std.c.ioctl(std.posix.STDOUT_FILENO, std.posix.T.IOCGWINSZ, &sizeWin);
std.log.info("return: {}", .{ret});
std.log.info("error: {}", .{std.posix.errno(ret)});
}
Output:
info: return: 0
info: error: .SUCCESS
I get .SUCCESS for both of the above examples when using the native backend. I believe that is also valid behaviour. A block local constant being placed on the stack isn’t surprising.
The following should fault on both LLVM and Zig’s own backend, but doesn’t. It only fails on LLVM. A container level constant declaration really should be placed in .rodata in both cases.
const sizeWin: std.posix.winsize = undefined;
pub fn main() !void {
const ret = std.c.ioctl(std.posix.STDOUT_FILENO, std.posix.T.IOCGWINSZ, &sizeWin);
std.log.info("return: {}", .{ret});
std.log.info("error: {}", .{std.posix.errno(ret)});
}