Skip to content

Conversation

@RalfJung
Copy link
Member

The old note didn't make it clear that the transmute is also illegal when it occurs nested inside a field. We already have the framework of "valid values" for this, so let's just use that also for this extra restriction.

Furthermore, there's another way to cause UB with provenance during const evaluation: by having a pointer whose bytes are mixed up.

@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Nov 16, 2025
@theemathas
Copy link
Contributor

theemathas commented Nov 16, 2025

This text currently does not cover the validity of the following in consteval:

  • str metadata (presumably the same as slice metadata)
  • closures, async blocks, and async closures (I have no idea how this works. I'm currently testing this.)

@RalfJung RalfJung force-pushed the const-eval-provenance-ub branch from 553a6a8 to c0c2fb2 Compare November 16, 2025 10:16
@RalfJung
Copy link
Member Author

str metadata (presumably the same as slice metadata)

This is already defined to be the same as &[u8].

closures, async blocks, and async closures (I have no idea how this works. I'm currently testing this.)

These are just structs, from an opsem perspective. We don't currently list them at all, even outside the const-eval clause.

@theemathas
Copy link
Contributor

My understanding is that async blocks behave more like unions? I'm not sure.

@theemathas
Copy link
Contributor

The current wording also doesn't prohibit mixing pointer fragments with different offsets, like in rust-lang/rust#146291

@RalfJung
Copy link
Member Author

The current wording also doesn't prohibit mixing pointer fragments with different offsets, like in rust-lang/rust#146291

The wording is "all bytes must be fragments of the same original pointer value in the correct order". "same pointer value" means same address/offset and same provenance.

@RalfJung
Copy link
Member Author

My understanding is that async blocks behave more like unions? I'm not sure.

More like a weird kind of enum. Anyway, they are container types that have fields, and we recurse into them like we recurse into structs and enums.

If you think we should be more explicit about closures and async lowering, please file an issue; that is entirely orthogonal to the const-eval clause.

@theemathas
Copy link
Contributor

Turns out that async blocks in const is gated behind an unstable feature, so that's a non-issue for the purposes of the reference.

Comment on lines 217 to 224
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.

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.
Copy link
Contributor

@traviscross traviscross Nov 18, 2025

Choose a reason for hiding this comment

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

It'd be good to add an example or two for this section (similar to the examples we looked at on the lang side that motivated the recent changes). That would also help make clear what we mean by a pointer fragment, apropos of the question @ehuss is about to ask.

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 },
}

@RalfJung RalfJung force-pushed the const-eval-provenance-ub branch from c0c2fb2 to be589ef Compare November 19, 2025 07:47
@RalfJung RalfJung force-pushed the const-eval-provenance-ub branch from e8f09a4 to 0cea1ca Compare November 19, 2025 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: The marked PR is awaiting review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants