Both the Rust reference and the Rustonomicon clearly state that "producing" a dangling reference is Undefined Behaviour.
Take this code snippet for example:
fn main() {
let p: std::ptr::NonNull<u8> = std::ptr::NonNull::dangling();
#[allow(unused_variables)]
let r: &u8 = unsafe { std::mem::transmute::<_, _>(p) };
}
Running it through Miri in the playground produces:
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0x1 is unallocated)
--> src/main.rs:4:27
|
4 | let r: &u8 = unsafe { std::mem::transmute::<_, _>(p) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x1 is unallocated)
|
= 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 `main` at src/main.rs:4:27
Of course, the Rust language is free to define as much stuff as UB as the creators want. What I am wondering is what the advantage of this Undefined Behaviour rule is (commonly, UB is introduced in a language to allow optimizations or simplify things).
Yet, according to the reference as linked above, the Undefined Behaviour may already be triggered by just writing a dangling reference to a local,and I fail to come up with a use for that.
So:
- How can producing (not dereferencing) a dangling reference in Rust cause UB?
- And can that UB be observed, without dereferencing the reference?