Is creating a null refrence safe if it's not used?

I just want to ask a quick question:
When I cast a pointer to reference, does that give the compiler any guarantees even if I don't ever use the reference?
I'm not asking whether it's undefined behavior - I'm sure it is, but I'd also assume that when the reference is never used, it may practically not cause any problems, but I'm not sure as the Rust compiler and the LLVM backend have ways to break code through things like alias analysis if you rely on non-standard behavior. Can anyone who knows the compiler answer me?

Whether something practically causes problems doesn't make something safe. You are correct in that it is undefined behavior, and therefore unsafe.

1 Like

The compiler sometimes saves space by using invalid bit patterns, like a null reference, to represent the discriminant in an enum. In particular, you might see Some(ub_nullref) act like None when you don't expect it to.

2 Likes

Yes it does. It gives all references the LLVM annotation "dereferencable", which means that the compiler can assume that it is not null. For example, it might conclude that any code path that involves such as cast is unreachable code and just optimize it out.

7 Likes
let p: *const () = 0 as _;
let p: &'_ () = unsafe { &*p };
assert!(Some(p).is_some());

yields assertion failed: Some(p).is_some()


A scariest one:

#![feature(never_type)]

fn main ()
{
    let p: *const ! = 0 as _;
    let b: bool;
    if false {
        b = true;
    } else {
        let _p: &'_ ! = unsafe { &*p };
    }
    dbg!(b);
}

A nice mental model for these things1, is that the moment you create a Rust reference, you have just asserted to the compiler / language that the pointer is valid to be read-dereferenced (dereferenceable attribute), so that the compiler is allowed to insert spurious dereferences of the reference even if you don't have them in your code.

1 even though it may be a tad too strict in some cases (but better safe than sorry!), since the status quo right now seems to point to validity of the referee being not a validity but a safety invariant of the reference (e.g., with the never type example above, using a transmute converts the runtime crash into a compile error). But even if that "relaxation" were to happen, being non-NULL and well-aligned is still a validity invariant.

6 Likes