Here is another puzzler. Let's say we have an extern,
extern fn foo(name: [*:0]const u8) callconv(.c) void;
But a mistake was made, and the actual underlying library accepts a null
for name
.
While the correct thing to do is to fix the extern signature with name: ?[*:0]const u8
, let's says we are not in control of that.
What are all the ways we can pass null
anyways?
Multiple answers, select all that apply:
foo(null);
foo(@bitCast(null));
foo(@ptrFromInt(0));
foo(@ptrCast(@as(?[*:0]const u8, null)));
foo(@ptrCast(@as([*:0]allowzero const u8, @ptrFromInt(0))));
foo(@allowzeroCast(@as([*:0]allowzero const u8, @ptrFromInt(0))));
foo(null: { var ptr: ?[*:0]const u8 = null; _ = &ptr; break :null @ptrFromInt(@intFromPtr(ptr)); });
- None of the above
Answer is after the whale.
Let's go through the options one at time.
A. foo(null);
Compiler error:
error: expected type '[*:0]const u8', found '@TypeOf(null)'
B. foo(@bitCast(null));
Compiler error:
error: cannot @bitCast to '[*:0]const u8'
C. foo(@ptrFromInt(0));
Compiler error:
error: pointer type '[*:0]const u8' does not allow address zero
D. foo(@ptrCast(@as(?[*:0]const u8, null)));
Compiler error:
error: null pointer casted to type '[*:0]const u8'
E. foo(@ptrCast(@as([*:0]allowzero const u8, @ptrFromInt(0))));
Compiler error:
error: null pointer casted to type '[*:0]const u8'
F. foo(@allowzeroCast(@as([*:0]allowzero const u8, @ptrFromInt(0))));
Compiler error:
error: invalid builtin function: '@allowzeroCast'
G.
foo(null: { var ptr: ?[*:0]const u8 = null; _ = &ptr; break :null @ptrFromInt(@intFromPtr(ptr)); });
This one actually compiles! But then panics at runtime:
panic: cast causes pointer to be null
H. None of the above
AFAIK, the Zig compiler/runtime is too smart to be tricked. The only way is to fix the extern signature.
Motivating issue: https://github.com/ziglang/zig/issues/19946
Top comments (1)
Of course you can always lie...
with cheater.c: