Miri on the Rust Playground did not forbid this:
fn main() {
let null_ptr = std::ptr::null::<()>();
let value = unsafe {
*null_ptr
};
dbg!(value);
}
Miri on the Rust Playground did not forbid this:
fn main() {
let null_ptr = std::ptr::null::<()>();
let value = unsafe {
*null_ptr
};
dbg!(value);
}
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.
This was actually specified not long ago to be defined: