-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathgui_uyp3mCj77FS8.rst.inc
More file actions
280 lines (206 loc) · 11.9 KB
/
gui_uyp3mCj77FS8.rst.inc
File metadata and controls
280 lines (206 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
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*.
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`.
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