Unsafe 1 @WaffleLapkin @BoxyUwU @m-ou-se @Victoronz

Warning: this quiz is still "work-in-progress", some questions might not have good explanations (or any at all), formatting/structure/titles/etc are not final, and so on. You might want to return here on a later date.

Note: the question is whether the code, as executed, is UB or whether it is sound. When the snippet has UB, explain exactly where it is UB and why.

#![allow(deref_nullptr)]

fn main() {
    // 1. UB?
    unsafe {
        _ = *std::ptr::null::<u32>();
    }
}
#![allow(deref_nullptr, unused_parens)]

fn main() {
    // 2. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>());
    }
}
#![allow(deref_nullptr, unused_parens)]

fn main() {
    // 3. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>(),);
    }
}
#![allow(deref_nullptr, unused_braces)]

fn main() {
    // 4. UB?
    unsafe {
        _ = { *std::ptr::null::<u32>() };
    }
}
#![allow(deref_nullptr)]

fn main() {
    // 5. UB?
    _ = unsafe { *std::ptr::null::<u32>() };
}
Solution

Examples 1 and 2 are fine, while 3, 4 and 5 are UB:

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_3.rs:6:14
  |
6 |         _ = (*std::ptr::null::<u32>(),);
  |              ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = 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 examples/unsafe_1_3.rs:6:14: 6:38

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_4.rs:6:15
  |
6 |         _ = { *std::ptr::null::<u32>() };
  |               ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = 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 examples/unsafe_1_4.rs:6:15: 6:39

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
 --> examples/unsafe_1_5.rs:5:18
  |
5 |     _ = unsafe { *std::ptr::null::<u32>() };
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
  |
  = 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 examples/unsafe_1_5.rs:5:18: 5:42

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

Loading a value from a null pointer is undefined behavior in Rust. However, dereferencing a pointer does not always cause a load, it only creates a place that can then be implicitly coerced to a value.

In examples 1 and 2 the dereference produces a place which is immediately discarded by the assignment to _ (note that parenthesis do not affect anything other than precedence of operators).

In example 3 the place created by the dereference is coerced to a value because (...,) creates a single element tuple (note the ,!).

In examples 4 and 5 the place created by the dereference is coerced to a value, because it is returned from a block (note that normal and unsafe blocks behave the same) which causes UB.

To learn more about differences between places and values read an article by Ralf Jung, "What is a place expression?".