.? on a pointer that came back from C is an assertion, not a check. It says null is impossible here. In a safety-checked build a null panics, and in ReleaseFast or ReleaseSmall it is undefined behaviour. For malloc that claim is false by definition.
const p = c.malloc(n).?; // asserts non-null
const q = c.malloc(n) orelse return error.OutOfMemory;
The second line returns the failure to the caller, which is the honest version. Functions returning [*c]u8 are worse, because the type has no ? to remind anyone. Coercing a C pointer to a non-optional pointer is the same assertion with no syntax at all. The Zig documentation calls a zero address there safety-checked illegal behaviour.
So in wrappers I read, every C pointer goes through an optional first, and orelse names the error. What I have not decided is which error. error.OutOfMemory is right for malloc and wrong for many functions that return null.