Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
718104f
feat: split into own file
PLeVasseur Dec 15, 2025
0d91f92
feat: remove description related to union
rcseacord Dec 15, 2025
476b76a
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 17, 2025
9743036
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 17, 2025
26eaa0f
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 17, 2025
68c48f2
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 18, 2025
aaa83a4
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 18, 2025
a4c6c83
Update gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 18, 2025
66b5a4b
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Dec 18, 2025
e456a33
Update guideline on reading uninitialized memory
rcseacord Jan 2, 2026
a95c087
Update citations in gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 2, 2026
cebdd28
Remove unnecessary newline in gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 2, 2026
6ce3ddb
fix(guidelines): annotate unsafe examples
PLeVasseur Jan 19, 2026
26883e6
fix(guidelines): silence example warnings
PLeVasseur Jan 19, 2026
39fcb24
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 20, 2026
13c0267
Update noncompliant example explanation
rcseacord Jan 20, 2026
54fda06
Update comments for clarity in Rust examples
rcseacord Jan 20, 2026
5f37374
Merge branch 'rustfoundation:main' into doc/no-uninit-value
rcseacord Jan 21, 2026
0524074
Update function references to include std::mem:: prefix
rcseacord Jan 21, 2026
6e2cd30
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
3afff16
Simplify guidelines on uninitialized memory usage
rcseacord Jan 21, 2026
43b8103
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
98863df
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
ee4a86a
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
fc521a1
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
347d9ca
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
1ef98f2
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
e9efabf
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
f84f500
Update src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
rcseacord Jan 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 280 additions & 0 deletions src/coding-guidelines/values/gui_uyp3mCj77FS8.rst.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
.. SPDX-License-Identifier: MIT OR Apache-2.0
SPDX-FileCopyrightText: The Coding Guidelines Subcommittee Contributors

.. default-domain:: coding-guidelines

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

Do not read uninitialized memory of any non-union type as a typed value :cite:`gui_uyp3mCj77FS8:RUSTNOMICON-UNINIT`.
This is sometimes referred to as *transmuting* or *read-at-type*.
Copy link
Collaborator

@felix91gr felix91gr Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you say is the difference between this and std::mem::transmute? Maybe we ought to point out that this is not the same, since transmute is quite the famous unsafe function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felix91gr I got this information from @workingjubilee
I believe these things are roughly equivalent in the context they are used here in that they are all typed reads.

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
<https://coding-guidelines.arewesafetycriticalyet.org/coding-guidelines/types-and-traits/index.html#gui_UnionPartialInit>`_.

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

* :std:`std::mem::MaybeUninit::assume_init_drop`
* :std:`std::mem::MaybeUninit::assume_init_mut`
* :std:`std::mem::MaybeUninit::assume_init_read`
* :std:`std::mem::MaybeUninit::assume_init_ref`
* :std:`std::mem::MaybeUninit::array_assume_init`

Calling any of these functions on memory that is not fully initialized is undefined behavior :cite:`gui_uyp3mCj77FS8:RUST-REF-BEHAVIOR`.

.. rationale::
:id: rat_kjFRrhpS8Wu6
:status: draft

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

Memory must be properly initialized according to the requirements of the variable's type :cite:`gui_uyp3mCj77FS8: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::
:id: non_compl_ex_Qb5GqYTP6db1
:status: draft

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

.. rust-example::
:miri: expect_ub
:warn: allow

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::
:id: compl_ex_Ke869nSXuShV
:status: draft

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``.

.. rust-example::
: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::
:id: non_compl_ex_Qb5GqYTP6db4
:status: draft

This noncompliant example creates a pointer from uninitialized memory.

Not all bit patterns are valid pointers for all operations (e.g., provenance rules) :cite:`gui_uyp3mCj77FS8:UCG-VALIDITY`.

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

.. rust-example::
:miri: expect_ub
:warn: allow

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::
:id: non_compl_ex_Qb5GqYTP6db2
:status: draft

This noncompliant example creates a reference from uninitialized memory.

Creating a reference from arbitrary or uninitialized bytes is undefined behavior :cite:`gui_uyp3mCj77FS8:RUST-REF-BEHAVIOR`.
Copy link
Collaborator

@felix91gr felix91gr Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is entirely correct. A reference could be created from arbitrary bytes, e.g.

let bytes = 999u32.to_be_bytes();
let nine_nine_nine = u32::from_be_bytes(bytes);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find this any longer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? :O

You can't find the sentence that says "Creating a reference from arbitrary or uninitialized bytes is undefined behavior"?

It should be at line 119


References must be valid, aligned, dereferenceable, and non-null :cite:`gui_uyp3mCj77FS8:UCG-VALIDITY`. Uninitialized memory cannot satisfy these requirements.

.. rust-example::
:miri: expect_ub
:warn: allow

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::
:id: non_compl_ex_Qb5GqYTP6db3
:status: draft

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.

.. rust-example::
:miri: expect_ub

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::
:id: non_compl_ex_Qb5GqYTP6db5
:status: draft

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.

.. rust-example::
:miri: expect_ub

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::
:id: compl_ex_Ke869nSXuShW
:status: draft

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

.. rust-example::
: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::
:id: bib_WNCi5njUWLuY
:status: draft

.. list-table::
:header-rows: 0
:widths: auto
:class: bibliography-table

* - :bibentry:`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.

* - :bibentry:`gui_uyp3mCj77FS8:RUSTNOMICON-UNINIT`
- The Rust Project Developers. "The Rustonomicon - Uninitialized Memory." https://doc.rust-lang.org/nomicon/uninitialized.html.

* - :bibentry:`gui_uyp3mCj77FS8:RUST-REF-BEHAVIOR`
- The Rust Project Developers. "The Rust Reference - Behavior considered undefined." https://doc.rust-lang.org/reference/behavior-considered-undefined.html.

* - :bibentry:`gui_uyp3mCj77FS8:MAYBEUNINIT-DOC`
- The Rust Project Developers. "std::mem::MaybeUninit - Rust Standard Library Documentation." https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html.

* - :bibentry:`gui_uyp3mCj77FS8:FERROCENE-SPEC`
- Ferrocene GmbH. "Ferrocene Language Specification." https://spec.ferrocene.dev/.

* - :bibentry:`gui_uyp3mCj77FS8:MISRA-RUST`
- MISRA Consortium Limited. "MISRA Rust Guidelines (Draft)." https://misra.org.uk/.

* - :bibentry:`gui_uyp3mCj77FS8:ISO-26262`
- International Organization for Standardization. "ISO 26262 - Road vehicles - Functional safety." https://www.iso.org/standard/68383.html.

* - :bibentry:`gui_uyp3mCj77FS8:IEC-61508`
- International Electrotechnical Commission. "IEC 61508 - Functional Safety of Electrical/Electronic/Programmable Electronic Safety-related Systems." https://www.iec.ch/functional-safety.

* - :bibentry:`gui_uyp3mCj77FS8:RUST-SAFETY-CRITICAL-WG`
- Rust Foundation. "Rust Safety-Critical Consortium." https://github.com/rust-lang/safety-critical-consortium.

* - :bibentry:`gui_uyp3mCj77FS8:UCG-VALIDITY`
- Rust Unsafe Code Guidelines. "Validity and Safety Invariant." https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#validity-and-safety-invariant.

* - :bibentry:`gui_uyp3mCj77FS8:CERT-RUST`
- Carnegie Mellon University Software Engineering Institute. "SEI CERT Rust Coding Standard." https://wiki.sei.cmu.edu/confluence/display/rust
1 change: 1 addition & 0 deletions src/coding-guidelines/values/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
Values
======

.. include:: gui_uyp3mCj77FS8.rst.inc