Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions src/behavior-considered-undefined.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,6 @@ r[undefined.asm]
* Incorrect use of inline assembly. For more details, refer to the [rules] to
follow when writing code that uses inline assembly.

r[undefined.const-transmute-ptr2int]
* **In [const context](const_eval.md#const-context)**: transmuting or otherwise
reinterpreting a pointer (reference, raw pointer, or function pointer) into
some allocation as a non-pointer type (such as integers).
'Reinterpreting' refers to loading the pointer value at integer type without a
cast, e.g. by doing raw pointer casts or using a union.

r[undefined.runtime]
* Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented.
* For assumptions specifically related to unwinding, see the [panic documentation][unwinding-ffi].
Expand Down Expand Up @@ -119,7 +112,7 @@ the pointer that was dereferenced, *not* the type of the field that is being
accessed.

r[undefined.misaligned.load-store]
Note that a place based on a misaligned pointer only leads to Undefined Behavior
Note that a place based on a misaligned pointer only leads to undefined behavior
when it is loaded from or stored to.

r[undefined.misaligned.raw]
Expand Down Expand Up @@ -221,6 +214,31 @@ r[undefined.validity.valid-range]
> [!NOTE]
> `rustc` achieves this with the unstable `rustc_layout_scalar_valid_range_*` attributes.

r[undefined.validity.const-provenance]
* **In [const context](const_eval.md#const-context)**: In addition to what is described above,
further provenance-related requirements apply during const evaluation.
Any value that holds pure integer data (the `i*`/`u*`/`f*` types as well as `bool` and `char`, enum discriminants, and slice metadata) must not carry any provenance.
Any value that holds pointer data (references, raw pointers, function pointers, and `dyn Trait` metadata) must either carry no provenance,
or all bytes must be fragments of the same original pointer value in the correct order.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem like "pointer fragments" is defined anywhere. Would it be possible to come up with a definition somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's tricky to define in isolation. Maybe it's better to avoid the term and just say all bytes must "come from" the same original pointer value?

The longer answer is that during const-eval, a byte doesn't look quite like what we have defined in the reference currently. It's more like

enum Byte {
  Uninit,
  /// Initialized byte without provenance.
  Init(u8),
  /// Pointer fragment. `idx` is in the range `0..ptr_size`.
  PointerFragment { ptr: Pointer, idx: u8 },
}


This implies that transmuting or otherwise reinterpreting a pointer (reference, raw pointer, or function pointer) into a non-pointer type (such as integers) is undefined behavior if the pointer had provenance.

> [!EXAMPLE]
> All of the following are UB:
> ```rust,compile_fail
> const REINTERPRET_PTR_AS_INT: usize = {
> let ptr = &0;
> unsafe { (&raw const ptr as *const usize).read() }
> };
>
> const PTR_BYTES_IN_WRONG_ORDER: &i32 = {
> let mut ptr = &0;
> let ptr_bytes = &raw mut ptr as *mut std::mem::MaybeUninit::<u8>;
> unsafe { std::ptr::swap(ptr_bytes.add(1), ptr_bytes.add(2)) };
> ptr
> };
> ```

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
Expand Down