From 93d25cc5e408e9eab0b77070ecdf49774c296c92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Aug 2026 23:25:02 +0200 Subject: [PATCH 1/2] nail down the final validity rules: references and unions --- src/behavior-considered-undefined.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 935f0dd9fa..e6b6feba72 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -145,10 +145,13 @@ r[undefined.validity.struct] * A `struct`, tuple, and array requires all fields/elements to be valid at their respective type. r[undefined.validity.union] -* For a `union`, the exact validity requirements are not decided yet. Obviously, all values that can be created entirely in safe code are valid. If the union has a [zero-sized] field, then every possible value is valid. Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438). +* For a `union`, there are no validity requirements. All byte sequences are valid union values. r[undefined.validity.reference-box] -* A reference or [`Box`] must be aligned and non-null, it cannot be [dangling], and it must point to a valid value (in case of dynamically sized types, using the actual dynamic type of the pointee as determined by the [metadata]). Note that the last point (about pointing to a valid value) remains a subject of some debate. +* A reference or [`Box`] must be aligned and non-null, it cannot be [dangling], and the pointee type `T` must be *inhabited*. + + The exact classification of inhabited types is unspecified, similar to the size and alignment of types. + However, types that can be constructed from safe code are definitely inhabited. r[undefined.validity.wide] * The [metadata] of a wide reference, [`Box`], or raw pointer must match the type of the [unsized tail]: @@ -195,8 +198,11 @@ r[undefined.validity.const-provenance] > }; > ``` -r[undefined.validity.undef] -**Note:** Uninitialized memory is also implicitly invalid for any type that has a restricted set of valid values. In other words, the only cases in which reading uninitialized memory is permitted are inside `union`s and in "padding" (the gaps between the fields of a type). +> [!NOTE] +> The definition above implies that uninitialized memory is invalid everywhere except inside `union`s and in "padding" (the gaps between the fields of a type). + +> [!WARNING] +> Just because a value is *valid* does not mean that it is *safe to use*. A value being *valid* merely means that creating the value does not cause immediate undefined behavior; such UB can still be caused later, even by safe operations. For instance, consider that `&str` pointing to initialized non-UTF8 data is *valid* as defined above, but passing such a value to a safe function can cause undefined behavior. As a more extreme example, consider that `&[u8]` pointing to allocated but uninitialized memory is *valid*, but one can trivially cause UB simply by accessing an element of the slice. Generally, only values you can construct in safe code are *safe to use*. [`bool`]: types/boolean.md [`const`]: items/constant-items.md From c8ce01e71a71c7a64ea3c6918e652a69d6d72d1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Aug 2026 11:23:54 +0200 Subject: [PATCH 2/2] make 'inhabited' check account for dynamic information in metadata --- src/behavior-considered-undefined.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index e6b6feba72..c78e6dbb73 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -152,6 +152,8 @@ r[undefined.validity.reference-box] The exact classification of inhabited types is unspecified, similar to the size and alignment of types. However, types that can be constructed from safe code are definitely inhabited. + For unsized types, this check considers dynamic information from the metadata: + In particular, if `T` has an unsized tail of slice type `[U]`, and if `U` is uninhabited, and if the length encoded in the metadata is non-zero, then the pointee is uninhabited. r[undefined.validity.wide] * The [metadata] of a wide reference, [`Box`], or raw pointer must match the type of the [unsized tail]: