Skip to content

Commit d9d7249

Browse files
authored
Revise compliant and non-compliant examples in values.rst
Updated examples to clarify compliant and non-compliant behavior with uninitialized padding in Rust.
1 parent fba8889 commit d9d7249

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

src/coding-guidelines/values.rst

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,12 @@ Values
215215
let u = U { x: 255 }; // 255 is not a valid bool representation
216216
let b = unsafe { u.b }; // UB — invalid bool
217217
218-
.. compliant_example::
219-
:id: compl_ex_Ke869nSXuShT
218+
.. non_compliant_example::
219+
:id: non_compl_ex_Qb5GqYTP6db4
220220
:status: draft
221221

222-
In this compliant example, ``s`` contains uninitialized padding and ``copy_of_s`` contains a copy of those uninitialized padding bytes.
223-
Both values are fully valid as long as only their fields are read.
224-
``#[derive(Copy, Clone)]`` allows ``S`` to be bitwise copied.
225-
Bitwise copying does not read the padding, it just copies whatever bytes are present.
226-
Uninitialized bytes can be copied (including padding).
227-
Reading padding is undefined behavior, but copying it is not.
222+
This noncompliant example has undefined behavior when ``assume_init()`` is called on ``tmp`` because
223+
not all the fields of ``struct S`` have been initialized.
228224

229225
.. code-block:: rust
230226
@@ -242,17 +238,44 @@ Values
242238
243239
unsafe {
244240
(*tmp.as_mut_ptr()).a = a;
245-
tmp.assume_init()
241+
tmp.assume_init() // Error: UB
246242
}
247243
}
248244
249245
fn main() {
250246
let s = make_s(10);
251-
println!("s.a = {}", s.a); // OK
252-
println!("s.b = {}", s.b); // Error: UB
247+
println!("s.a = {}, s.b = {}", s.a, s.b);
248+
}
253249
254-
let copy_of_s = s; // OK
255-
println!("copy_of_s.a = {}", copy_of_s.a); // OK
256-
println!("copy_of_s.b = {}", copy_of_s.b); // Error: UB
250+
.. compliant_example::
251+
:id: compl_ex_Ke869nSXuShT
252+
:status: draft
253+
254+
This compliant example example is free from undefined behavior, even though the three bytes of padding between ``s.a`` and ``s.b`` is uninitialized.
255+
Padding bytes do not need to be initialized.
256+
257+
.. code-block:: rust
258+
259+
use std::mem::MaybeUninit;
260+
261+
#[repr(C)]
262+
#[derive(Copy, Clone)]
263+
struct S {
264+
a: u8,
265+
b: u32,
266+
}
267+
268+
fn make_s(a: u8, b: u32) -> S {
269+
let mut tmp = MaybeUninit::<S>::uninit();
270+
271+
unsafe {
272+
(*tmp.as_mut_ptr()).a = a;
273+
(*tmp.as_mut_ptr()).b = b;
274+
tmp.assume_init()
275+
}
257276
}
258277
278+
fn main() {
279+
let s = make_s(10, 42);
280+
println!("s.a = {}, s.b = {}", s.a, s.b);
281+
}

0 commit comments

Comments
 (0)