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 u16
let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
let very_random_number = if random_number <= 100 {
unsafe {
// Safety: all bitpatterns are valid for u16
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 bitpatterns are valid for a u16
(and all integer types in general), creating an integer value from uninitialized memory is still undefined behavior. Since uninitialized memory does not have a fixed value, it cannot be used to generate an integer, which are for fixed bit patterns. More details can be found in the MaybeUnint
documentation.