Skip to content

Annotating the type of transmute of a const causes a reborrow and retag, increasing the amount of UB #146917

@theemathas

Description

@theemathas

I tried this code:

use std::mem::transmute;
const A: &u8 = unsafe { transmute(&0u64) };
fn main() {
    // This is ok
    let _x: &u64 = unsafe { transmute::<_, _>(A) };
    // We can even read through the reference
    let _y = *_x;
    // This is UB
    let _z: &u64 = unsafe { transmute::<&_, _>(A) };
}

I expected the transmutes to either be both OK or both UB. Instead, only the second transmute is detected as UB by Miri.

error: Undefined Behavior: trying to retag from <298> for SharedReadOnly permission at alloc3[0x1], but that tag does not exist in the borrow stack for this location
 --> src/main.rs:9:29
  |
9 |     let _z: &u64 = unsafe { transmute::<&_, _>(A) };
  |                             ^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at alloc3[0x0..0x8]
  |
  = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
  = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <298> was created by a SharedReadOnly retag at offsets [0x0..0x1]
 --> src/main.rs:9:48
  |
9 |     let _z: &u64 = unsafe { transmute::<&_, _>(A) };
  |                                                ^
  = note: BACKTRACE (of the first span):
  = note: inside `main` at src/main.rs:9:29: 9:50

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

The relevant MIR is:

    bb0: {
        _1 = const A as &u64 (Transmute);
        _2 = copy (*_1);
        _4 = const A;
        _3 = move _4 as &u64 (Transmute);
        return;
    }

It seems to me that:

  • The A const has provenance that can access the entire 8 bytes of the u64.
  • transmute is not a typed copy, so it preserves that provenance when the type isn't annotated
  • Annotating the type, for some reason, causes a typed copy of A to happen before transmuting, shrinking the provenance.

(Note that other means of causing a typed copy, such as adding a brace so it's transmute::<_, _>({A}), also causes UB.)

See also #143671 and #140123, where annotating a type changes the behavior of the program.

Meta

Reproducible on the playground with Rust version 1.92.0-nightly (2025-09-21 9f32ccf35fb877270bc4) and Miri version 0.1.0 (2025-09-21 9f32ccf35f)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)A-miriArea: The miri toolC-bugCategory: This is a bug.I-lang-radarItems that are on lang's radar and will need eventual work or consideration.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamneeds-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions