Unsafe 2 @WaffleLapkin @BoxyUwU

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.

use std::mem::MaybeUninit;

fn main() {
    // Safety: all bitpatterns are valid for u8
    let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };

    let very_random_number = if random_number <= 100 {
        unsafe {
            // Safety: all bitpatterns are valid for u32
            let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
            // Safety: The `random_number` is in bounds
            *rng_array.get_unchecked(random_number as usize)
        }
    } else {
        // chosen by a fair dice roll
        4
    };

    dbg!(very_random_number);
}
Solution
warning: the type `u8` does not permit being left uninitialized
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |                                      |
  |                                      this code causes undefined behavior when executed
  |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: integers must be initialized
  = note: `#[warn(invalid_value)]` on by default

warning: the type `[u32; 100]` does not permit being left uninitialized
  --> examples/unsafe_2.rs:10:41
   |
10 |             let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                                         |
   |                                         this code causes undefined behavior when executed
   |                                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
   |
   = note: integers must be initialized

error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
  |
  = 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_2.rs:5:38: 5:73

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

error: aborting due to 1 previous error; 2 warnings emitted

Even though all initialized bitpatterns are valid for integer types, creating an integer value from uninitialized memory is still undefined behavior. More details can be found in the MaybeUninit documentation.

Careful readers may also have noticed that there is an index out of bounds error from checking random_number <= 100 instead of random_number < 100. While this is logically incorrect, it does not result in any UB as the previous line when creating random_number is UB and thus all future lines are not executed.