Skip to content

Commit 7713f0d

Browse files
PLeVasseurmanhatsu
authored andcommitted
feat: split into own file
1 parent 34d0707 commit 7713f0d

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
.. SPDX-License-Identifier: MIT OR Apache-2.0
2+
SPDX-FileCopyrightText: The Coding Guidelines Subcommittee Contributors
3+
4+
.. default-domain:: coding-guidelines
5+
6+
.. guideline:: Do not create values from uninitialized memory except for union fields
7+
:id: gui_uyp3mCj77FS8
8+
:category: mandatory
9+
:status: draft
10+
:release: <TODO>
11+
:fls: fls_6lg0oaaopc26
12+
:decidability: undecidable
13+
:scope: system
14+
:tags: undefined-behavior, unsafe
15+
16+
A program shall not create a value of any type from uninitialized memory,
17+
except when accessing a field of a union type,
18+
where such reads are explicitly defined to be permitted even if the bytes of that field are uninitialized.
19+
It is prohibited to interpret uninitialized memory as a value of any Rust type such as a
20+
primitive, aggregate, reference, pointer, struct, enum, array, or tuple.
21+
22+
**Exception:** You can access a field of a union even when the backing bytes of that field are uninitialized provided that:
23+
24+
- The resulting value has an unspecified but well-defined bit pattern.
25+
- Interpreting that value must still comply with the requirements of the accessed type
26+
(e.g., no invalid enum discriminants, no invalid pointer values, etc.).
27+
28+
For example, reading an uninitialized u32 field of a union is allowed;
29+
reading an uninitialized bool field is disallowed because not all bit patterns are valid.
30+
31+
.. rationale::
32+
:id: rat_kjFRrhpS8Wu6
33+
:status: draft
34+
35+
Rust's memory model treats all types except unions as having an invariant that all bytes must be initialized before a value may be constructed.
36+
Reading uninitialized memory:
37+
38+
- creates undefined behavior for most types,
39+
- may violate niche or discriminant validity,
40+
- may create invalid pointer values, or
41+
- may produce values that violate type invariants.
42+
43+
The sole exception is that unions work like C unions: any union field may be read, even if it was never written.
44+
The resulting bytes must, however, form a valid representation for the field's type,
45+
which is not guaranteed if the union contains arbitrary data.
46+
47+
.. non_compliant_example::
48+
:id: non_compl_ex_Qb5GqYTP6db1
49+
:status: draft
50+
51+
This noncompliant example creates a value of type ``u32`` from uninitialized memory via
52+
`assume_init <https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init>`_:
53+
54+
.. rust-example::
55+
56+
use std::mem::MaybeUninit;
57+
58+
# fn main() {
59+
let x: u32 = unsafe { MaybeUninit::uninit().assume_init() }; // UB
60+
# }
61+
62+
.. compliant_example::
63+
:id: compl_ex_Ke869nSXuShU
64+
:status: draft
65+
66+
Types such as ``u8``, ``u16``, ``u32``, and ``i128`` allow all possible bit patterns.
67+
Provided the memory is initialized, there is no undefined behavior.
68+
69+
.. rust-example::
70+
71+
union U {
72+
n: u32,
73+
bytes: [u8; 4],
74+
}
75+
76+
# fn main() {
77+
let u = U { bytes: [0xFF, 0xEE, 0xDD, 0xCC] };
78+
let n = unsafe { u.n }; // OK — all bit patterns valid for u32
79+
# }
80+
81+
.. compliant_example::
82+
:id: compl_ex_Ke869nSXuShV
83+
:status: draft
84+
85+
This compliant example calls the ``write`` function to fully initialize low-level memory.
86+
87+
.. rust-example::
88+
89+
use std::mem::MaybeUninit;
90+
91+
# fn main() {
92+
let mut x = MaybeUninit::<u64>::uninit();
93+
x.write(42);
94+
let val = unsafe { x.assume_init() }; // OK — value was fully initialized
95+
# }
96+
97+
.. non_compliant_example::
98+
:id: non_compl_ex_Qb5GqYTP6db2
99+
:status: draft
100+
101+
Creating a reference from arbitrary or uninitialized bytes is always undefined behavior.
102+
References must be valid, aligned, properly dereferenceable, and non-null.
103+
Uninitialized memory cannot satisfy these invariants.
104+
105+
.. rust-example::
106+
107+
use std::mem::MaybeUninit;
108+
109+
# fn main() {
110+
let r: &u32 = unsafe { MaybeUninit::uninit().assume_init() }; // UB — invalid reference
111+
# }
112+
113+
.. non_compliant_example::
114+
:id: non_compl_ex_Qb5GqYTP6db4
115+
:status: draft
116+
117+
Not all bit patterns are valid pointers for all operations (e.g., provenance rules).
118+
You cannot create a pointer from unspecified bytes.
119+
Even a raw pointer type (e.g., ``*const T``) has validity rules.
120+
121+
.. rust-example::
122+
123+
use std::mem::MaybeUninit;
124+
125+
# fn main() {
126+
let p: *const u32 = unsafe { MaybeUninit::uninit().assume_init() }; // UB
127+
# }
128+
.. non_compliant_example::
129+
:id: non_compl_ex_Qb5GqYTP6db5
130+
:status: draft
131+
132+
Array elements must individually be valid values.
133+
134+
.. rust-example::
135+
136+
use std::mem::MaybeUninit;
137+
138+
# fn main() {
139+
let mut arr: [MaybeUninit<u8>; 4] = unsafe { MaybeUninit::uninit().assume_init() };
140+
let a = unsafe { std::mem::transmute::<_, [u8; 4]>(arr) }; // UB — not all elements initialized
141+
# }
142+
143+
.. compliant_example::
144+
:id: compl_ex_Ke869nSXuShT
145+
:status: draft
146+
147+
The following code reads a union field:
148+
149+
.. rust-example::
150+
151+
union U {
152+
x: u32,
153+
y: f32,
154+
}
155+
156+
# fn main() {
157+
let u = U { x: 123 }; // write to one field
158+
let f = unsafe { u.y }; // reading the other field is allowed
159+
# }
160+
161+
.. non_compliant_example::
162+
:id: non_compl_ex_Qb5GqYTP6db3
163+
:status: draft
164+
165+
Even though unions allow reads of any field, not all bit patterns are valid for a ``bool``.
166+
Unions do not relax type validity requirements.
167+
Only the read itself is allowed;
168+
the resulting bytes must still be a valid bool.
169+
170+
.. rust-example::
171+
172+
union U {
173+
b: bool,
174+
x: u8,
175+
}
176+
177+
# fn main() {
178+
let u = U { x: 255 }; // 255 is not a valid bool representation
179+
let b = unsafe { u.b }; // UB — invalid bool
180+
# }
181+
182+
.. compliant_example::
183+
:id: compl_ex_Ke869nSXuShW
184+
:status: draft
185+
186+
Accessing padding bytes is allowed if not interpreted as typed data:
187+
188+
.. rust-example::
189+
190+
#[repr(C)]
191+
struct S {
192+
a: u8,
193+
b: u32,
194+
}
195+
196+
# fn main() {
197+
let mut buf = [0u8; std::mem::size_of::<S>()];
198+
buf[0] = 10;
199+
buf[1] = 20; // writing padding is fine
200+
201+
let p = buf.as_ptr() as *const S;
202+
let s = unsafe { p.read_unaligned() }; // OK — all *fields* are initialized (padding doesn't matter)
203+
# }

src/coding-guidelines/values/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
Values
77
======
88

9+
.. include:: gui_uyp3mCj77FS8.rst.inc

0 commit comments

Comments
 (0)