Skip to content

drop_in_place on a pointer derived from &raw const of a static mut does not detect UB #4574

@theemathas

Description

@theemathas

Consider the following code:

use std::ptr::drop_in_place;

struct Thing(i32);

static mut STATIC: Thing = Thing(1);

fn works() {
    unsafe {
        drop_in_place((&raw const STATIC).cast_mut());
    }
}

fn fails() {
    let x = Thing(2);
    unsafe {
        drop_in_place((&raw const x).cast_mut());
    }
}

fn main() {
    works();
    fails();
}

I expected works() and fails() to either both be UB, or both be defined behavior. However, Miri reports UB only for the fails() function.

Miri error
error: Undefined Behavior: trying to retag from <298> for Unique permission at alloc155[0x0], but that tag only grants SharedReadOnly permission for this location
   --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:804:1
    |
804 | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at alloc155[0x0..0x4]
    |
    = 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..0x4]
   --> src/main.rs:16:23
    |
 16 |         drop_in_place((&raw const x).cast_mut());
    |                       ^^^^^^^^^^^^^^
    = note: BACKTRACE (of the first span):
    = note: inside `std::ptr::drop_in_place::<Thing> - shim(None)` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:804:1: 804:62
note: inside `fails`
   --> src/main.rs:16:9
    |
 16 |         drop_in_place((&raw const x).cast_mut());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `main`
   --> src/main.rs:22:5
    |
 22 |     fails();
    |     ^^^^^^^

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

Adding a Drop implementation that mutates the value does not change this behavior.

impl Drop for Thing {
    fn drop(&mut self) {
        self.0 = 3;
    }
}

Changing the original code to use static instead of static mut results in Miri detecting UB.

Miri error with `static`

error: Undefined Behavior: writing to alloc1 which is read-only
   --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:804:1
    |
804 | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::ptr::drop_in_place::<Thing> - shim(None)` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:804:1: 804:62
note: inside `works`
   --> src/main.rs:9:9
    |
  9 |         drop_in_place((&raw const STATIC).cast_mut());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `main`
   --> src/main.rs:21:5
    |
 21 |     works();
    |     ^^^^^^^

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

Discovered while experimenting with rust-lang/rust#146187.

Reproduced the problem on the playground with version 1.91.0-nightly (2025-09-09 7ad23f43a225546c0951).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions