Is dereferencing a NULL pointer to a ZST considered UB?

Miri on the Rust Playground did not forbid this:

fn main() {
    let null_ptr = std::ptr::null::<()>();

    let value = unsafe {
        *null_ptr
    };

    dbg!(value);
}
1 Like

There's no memory access happening (zero bytes to read), so logically there's nothing to forbid and this is useful for abstractions like Vec<ZST> which use NonNull::dangling() internally.

It should be noted that any reference to this null pointer IS UB.

UB:

let null_ptr = std::ptr::null::<()>();


let reference = unsafe { &*null_ptr };

Or if you actually allocate memory and not use a ZST:

fn main() {
    let null_ptr = std::ptr::null::<i32>();

    let value = unsafe {
        *null_ptr
    };

    dbg!(value);
}

EDIT: I just I knew I read about something relevant in rustonomicon:

Almost every operation with a ZST is a no-op since ZSTs have exactly one value, and therefore no state needs to be considered to store or load them. This actually extends to ptr::read and ptr::write: they won't actually look at the pointer at all.

Thanks to @chrefr for the reference.

If the size is 0, then the pointer is trivially never "dangling" (even if it is a null pointer).

So, this specific case is directly defined (so not UB) in the reference.

2 Likes

This was actually specified not long ago to be defined:

3 Likes