Checked - The Rustonomicon
Description: The Dark Arts of Advanced and Unsafe Rust Programming

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Checked Uninitialized Memory

Like C, all stack variables in Rust are uninitialized until a value is explicitly assigned to them. Unlike C, Rust statically prevents you from ever reading them until you do:

    fn main() {
        let x: i32;
        println!("{}", x);
    }

      |
    3 |     println!("{}", x);
      |                    ^ use of possibly uninitialized `x`

This is based off of a basic branch analysis: every branch must assign a value to `x` before it is first used. For short, we also say that “`x` is init” or “`x` is uninit”.

Interestingly, Rust doesn’t require the variable to be mutable to perform a delayed initialization if every branch assigns exactly once. However the analysis does not take advantage of constant analysis or anything like that. So this compiles:

    fn main() {
        let x: i32;

        if true {
            x = 1;
        } else {
            x = 2;
        }

        println!("{}", x);
    }

but this doesn’t:

    fn main() {
        let x: i32;
        if true {
            x = 1;
        }
        println!("{}", x);
    }

      |
    6 |     println!("{}", x);
      |                    ^ use of possibly uninitialized `x`

while this does:

    fn main() {
        let x: i32;
        if true {
            x = 1;
            println!("{}", x);
        }
        // Don't care that there are branches where it's not initialized
        // since we don't use the value in those branches
    }

Of course, while the analysis doesn’t consider actual values, it does have a relatively sophisticated understanding of dependencies and control flow. For instance, this works:

    #![allow(unused)]
    fn main() {
    let x: i32;

    loop {
        // Rust doesn't understand that this branch will be taken unconditionally,
        // because it relies on actual values.
        if true {
            // But it does understand that it will only be taken once because
            // we unconditionally break out of it. Therefore `x` doesn't
            // need to be marked as mutable.
            x = 0;
            break;
        }
    }
    // It also knows that it's impossible to get here without reaching the break.
    // And therefore that `x` must be initialized here!
    println!("{}", x);
    }

If a value is moved out of a variable, that variable becomes logically uninitialized if the type of the value isn’t Copy. That is:

    fn main() {
        let x = 0;
        let y = Box::new(0);
        let z1 = x; // x is still valid because i32 is Copy
        let z2 = y; // y is now logically uninitialized because Box isn't Copy
    }

However reassigning `y` in this example would require `y` to be marked as mutable, as a Safe Rust program could observe that the value of `y` changed:

    fn main() {
        let mut y = Box::new(0);
        let z = y; // y is now logically uninitialized because Box isn't Copy
        y = Box::new(1); // reinitialize y
    }

Otherwise it’s like `y` is a brand new variable.