Description
Consider the following program:
fn main() {
use core::ptr::*;
unsafe { dbg!(replace(null_mut(), ())); }
}
This was made a legal program in Rust 1.80, the preconditions state:
dst
must be valid for both reads and writes.dst
must be properly aligned.dst
must point to a properly initialized value of typeT
.
This is because in Rust 1.80 the following line was added to valid:
For operations of size zero, every pointer is valid, including the null pointer. The following points are only concerned with non-zero-sized accesses.
Nevertheless, running the above program results in undefined behavior:
error: Undefined Behavior: constructing invalid value: encountered a null reference
--> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1227:22
|
1227 | mem::replace(&mut *dst, src)
| ^^^^^^^^^ constructing invalid value: encountered a null reference
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `std::ptr::replace::<()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1227:22: 1227:31
note: inside `main`
--> src/main.rs:3:19
|
3 | unsafe { dbg!(replace(null_mut(), ())); }
| ^^^^^^^^^^^^^^^^^^^^^^^
Rather than changing the implementation of core::ptr::replace
, or an isolated change to the requirements of core::ptr::replace
, I would like to see the change to the definition of a valid pointer for ZSTs reverted, I've expanded more about my thoughts and provided more arguments in this T-opsem zulip thread. In short, I believe that unsoundness similar to the case here in core::ptr::replace
will keep happening as long as "dereferencing a pointer" and "reborrowing a pointer" have different requirements (which they do since Rust 1.80).