Values

Guideline: Do not read uninitialized memory of any non-union type as a typed value gui_uyp3mCj77FS8
status: draft
tags: undefined-behavior, unsafe
category: mandatory
decidability: undecidable
scope: system
release: <TODO>

Do not read uninitialized memory of any non-union type as a typed value [RUSTNOMICON-UNINIT]. This is sometimes referred to as transmuting or read-at-type. Memory can remain uninitialized if it is not read as a type.

Reading from a union is covered by Do not read from union fields that may contain uninitialized bytes.

Calling std::mem::MaybeUninit::assume_init [MAYBEUNINIT-DOC] or any of the following related functions is treated in the same manner as a typed read:

Calling any of these functions on memory that is not fully initialized is undefined behavior [RUST-REF-BEHAVIOR].

Rationale: rat_kjFRrhpS8Wu6
status: draft
parent needs: gui_uyp3mCj77FS8

Rust’s memory model requires that all bytes must be initialized before being read as a typed value [RUSTNOMICON-UNINIT] [FERROCENE-SPEC]. Reading uninitialized memory as a typed value is undefined behavior [RUST-REF-BEHAVIOR]. This guideline aligns with functional safety standards [ISO-26262] [IEC-61508] and secure coding practices.

Memory must be properly initialized according to the requirements of the variable’s type [UCG-VALIDITY]. For example, a variable of reference type must be aligned, non-null, and point to valid memory. Similarly, entirely uninitialized memory may have any content, while a bool must always be true or false. Consequently, reading an uninitialized bool is undefined behavior.

Non-Compliant Example: non_compl_ex_Qb5GqYTP6db1
status: draft
parent needs: gui_uyp3mCj77FS8

This noncompliant example extracts a value of type u32 from uninitialized memory within a MaybeUninit<T> container, which is undefined behavior.

undefined behavior
use std::mem::MaybeUninit;

fn main() {
    // Reading uninitialized memory as a typed value is undefined behavior
    let _x: u32 = unsafe { MaybeUninit::uninit().assume_init() }; // noncompliant
}
Compliant Example: compl_ex_Ke869nSXuShV
status: draft
parent needs: gui_uyp3mCj77FS8

This compliant example creates an uninitialized variable x of type MaybeUninit<u64>.

The code calls the write function to write the value 42 to x. The call to assume_init asserts that the value is initialized and extracts the value of type u64.

This call to assume_init is compliant with this rule because the memory of x has been properly initialized by the call to write(42).

This is the canonically safe pattern for using MaybeUninit.

miri
use std::mem::MaybeUninit;

fn main() {
    let mut x = MaybeUninit::<u64>::uninit();
    x.write(42);
    // SAFETY: 'x' is fully initialized
    let _val = unsafe { x.assume_init() }; // compliant
}
Non-Compliant Example: non_compl_ex_Qb5GqYTP6db4
status: draft
parent needs: gui_uyp3mCj77FS8

This noncompliant example creates a pointer from uninitialized memory.

Not all bit patterns are valid pointers for all operations (e.g., provenance rules) [UCG-VALIDITY].

As can be seen here, even the raw pointer type (*const T) has validity rules [RUST-REF-BEHAVIOR].

undefined behavior
use std::mem::MaybeUninit;

fn main() {
    // Undefined behavior creating a pointer from uninitialized memory
    let _p: *const u32 = unsafe { MaybeUninit::uninit().assume_init() }; // noncompliant
}
Non-Compliant Example: non_compl_ex_Qb5GqYTP6db2
status: draft
parent needs: gui_uyp3mCj77FS8

This noncompliant example creates a reference from uninitialized memory.

Creating a reference from arbitrary or uninitialized bytes is undefined behavior [RUST-REF-BEHAVIOR].

References must be valid, aligned, dereferenceable, and non-null [UCG-VALIDITY]. Uninitialized memory cannot satisfy these requirements.

undefined behavior
use std::mem::MaybeUninit;

fn main() {
    // Reading an invalid reference is undefined behavior
    let _r: &u32 = unsafe { MaybeUninit::uninit().assume_init() }; // noncompliant
}
Non-Compliant Example: non_compl_ex_Qb5GqYTP6db3
status: draft
parent needs: gui_uyp3mCj77FS8

This noncompliant example has undefined behavior because it creates an invalid reference.

The &u8 reference has stricter validity requirements than the raw pointer *const u8. While ptr::dangling() produces a non-null, well-aligned pointer, it does not point to valid, allocated memory.

The code writes a dangling raw pointer into memory and then calls assume_init(), asserting that this memory contains a valid reference. However, a dangling pointer is never a valid reference—even if you never dereference it. The mere existence of an invalid reference is undefined behavior.

undefined behavior
use std::mem::MaybeUninit;
use std::ptr;

fn create_ref() {
    let mut uninit: MaybeUninit<&u8> = MaybeUninit::uninit();
    unsafe {
        // write non-null and aligned address.
        (&raw mut uninit).cast::<*const u8>().write(ptr::dangling());
        // Undefined behavior occurs when asserting 'uninit' is a valid reference.
        let _init = uninit.assume_init(); // noncompliant
    }
}

fn main() {
    create_ref();
}
Non-Compliant Example: non_compl_ex_Qb5GqYTP6db5
status: draft
parent needs: gui_uyp3mCj77FS8

Array elements must individually be valid values. This noncompliant example creates an uninitialized array of four u8 values. The call to .assume_init asserting that the array is initialized is valid here because an array of MaybeUninit<u8> can contain uninitialized bytes. The call to std::mem::transmute reinterprets the [MaybeUninit<u8>; 4] as [u8; 4]. This is undefined behavior, because the bytes were never initialized. Even though all bit patterns (0-255) are valid for the u8 type, the values must be initialized.

MaybeUninit<u8> can hold uninitialized memory — that’s its purpose. u8 cannot hold uninitialized memory — all 8 bits must be defined. The transmute performs a typed read that asserts the bytes are valid u8 values. Reading uninitialized bytes as a concrete type is always undefined behavior.

undefined behavior
use std::mem::MaybeUninit;

fn main() {
    let arr: [MaybeUninit<u8>; 4] = unsafe { MaybeUninit::uninit().assume_init() };
    // Undefined behavior constructing an array of 'u8' from uninitialized memory.
    let _a = unsafe { std::mem::transmute::<_, [u8; 4]>(arr) }; // noncompliant
}
Compliant Example: compl_ex_Ke869nSXuShW
status: draft
parent needs: gui_uyp3mCj77FS8

This compliant example defines a C-layout struct with:

  • a: 1 byte at offset 0

  • 3 bytes of padding (to align b to 4 bytes)

  • b: 4 bytes at offset 4

  • Total size: 8 bytes

The variable buf is a fully, zero-initialized 8-byte buffer.

The first two bytes of buf are overwritten. The byte buffer buf pointer is cast to a pointer to S. The call to read_unaligned reads the struct without requiring alignment.

This example is compliant because:

  • All bytes are initialized (buffer was zero-initialized)

  • All fields have valid values (u8 and u32 accept any bit pattern)

  • Padding bytes don’t need to be any specific value

  • read_unaligned handles the alignment issue

miri
#[repr(C)]
#[derive(Debug)]
struct S {
    a: u8,
    b: u32,
}

fn main() {
    let mut buf = [0u8; std::mem::size_of::<S>()];
    buf[0] = 10;
    buf[1] = 20; // writing padding is fine

    let p = buf.as_ptr() as *const S;
    //  SAFETY: All fields are initialized (padding doesn't matter)
    let s = unsafe { p.read_unaligned() }; // compliant
    println!("{:?}", s);
}
Bibliography: bib_WNCi5njUWLuY
status: draft
parent needs: gui_uyp3mCj77FS8

[DO-178C]

RTCA, Inc. “DO-178C: Software Considerations in Airborne Systems and Equipment Certification.” https://store.accuristech.com/standards/rtca-do-178c?product_id=2200105.

[RUSTNOMICON-UNINIT]

The Rust Project Developers. “The Rustonomicon - Uninitialized Memory.” https://doc.rust-lang.org/nomicon/uninitialized.html.

[RUST-REF-BEHAVIOR]

The Rust Project Developers. “The Rust Reference - Behavior considered undefined.” https://doc.rust-lang.org/reference/behavior-considered-undefined.html.

[MAYBEUNINIT-DOC]

The Rust Project Developers. “std::mem::MaybeUninit - Rust Standard Library Documentation.” https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html.

[FERROCENE-SPEC]

Ferrocene GmbH. “Ferrocene Language Specification.” https://spec.ferrocene.dev/.

[MISRA-RUST]

MISRA Consortium Limited. “MISRA Rust Guidelines (Draft).” https://misra.org.uk/.

[ISO-26262]

International Organization for Standardization. “ISO 26262 - Road vehicles - Functional safety.” https://www.iso.org/standard/68383.html.

[IEC-61508]

International Electrotechnical Commission. “IEC 61508 - Functional Safety of Electrical/Electronic/Programmable Electronic Safety-related Systems.” https://www.iec.ch/functional-safety.

[RUST-SAFETY-CRITICAL-WG]

Rust Foundation. “Rust Safety-Critical Consortium.” https://github.com/rust-lang/safety-critical-consortium.

[UCG-VALIDITY]

Rust Unsafe Code Guidelines. “Validity and Safety Invariant.” https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#validity-and-safety-invariant.

[CERT-RUST]

Carnegie Mellon University Software Engineering Institute. “SEI CERT Rust Coding Standard.” https://wiki.sei.cmu.edu/confluence/display/rust