|
5 | 5 |
|
6 | 6 | Values |
7 | 7 | ====== |
| 8 | + |
| 9 | +.. guideline:: Do not create values from uninitialized memory except for union fields |
| 10 | + :id: gui_uyp3mCj77FS8 |
| 11 | + :category: mandatory |
| 12 | + :status: draft |
| 13 | + :release: <TODO> |
| 14 | + :fls: fls_6lg0oaaopc26 |
| 15 | + :decidability: undecidable |
| 16 | + :scope: system |
| 17 | + :tags: undefined-behavior |
| 18 | + |
| 19 | + A program shall not create a value of any type from uninitialized memory, except when accessing a field of a union type, where such reads are explicitly defined to be permitted even if the bytes of that field are uninitialized. |
| 20 | + It is prohibited to interpret uninitialized memory as a value of any Rust type (primitive, aggregate, reference, pointer, struct, enum, array, tuple, etc.) |
| 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 (e.g., no invalid enum discriminants, no invalid pointer values, etc.). |
| 26 | + |
| 27 | + For example, reading an uninitialized u32 field of a union is allowed; reading an uninitialized bool field is disallowed because not all bit patterns are valid. |
| 28 | + |
| 29 | + .. rationale:: |
| 30 | + :id: rat_kjFRrhpS8Wu6 |
| 31 | + :status: draft |
| 32 | + |
| 33 | + 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. Reading uninitialized memory: |
| 34 | + |
| 35 | + - creates undefined behavior for most types, |
| 36 | + - may violate niche or discriminant validity, |
| 37 | + - may create invalid pointer values, |
| 38 | + - or may produce values that violate type invariants. |
| 39 | + |
| 40 | + The sole exception is that unions work like C unions: any union field may be read, even if it was never written. The resulting bytes must, however, form a valid representation for the field’s type, which is not guaranteed if the union contains arbitrary data. |
| 41 | + |
| 42 | + .. non_compliant_example:: |
| 43 | + :id: non_compl_ex_Qb5GqYTP6db1 |
| 44 | + :status: draft |
| 45 | + |
| 46 | + The following code creates a value from uninitialized memory via assume_init: |
| 47 | + |
| 48 | + .. code-block:: rust |
| 49 | +
|
| 50 | + use std::mem::MaybeUninit; |
| 51 | +
|
| 52 | + let x: u32 = unsafe { MaybeUninit::uninit().assume_init() }; // UB |
| 53 | +
|
| 54 | + .. compliant_example:: |
| 55 | + :id: compl_ex_Ke869nSXuShT |
| 56 | + :status: draft |
| 57 | + |
| 58 | + The following code reads a union field: |
| 59 | + |
| 60 | + .. code-block:: rust |
| 61 | +
|
| 62 | + union U { |
| 63 | + x: u32, |
| 64 | + y: f32, |
| 65 | + } |
| 66 | +
|
| 67 | + let u = U { x: 123 }; // write to one field |
| 68 | + let f = unsafe { u.y }; // reading the other field is allowed |
0 commit comments