apilat
apilat

Reputation: 1510

Miri complains about UB when initializing and manually dropping MaybeUninit

I am writing code to initialize an array of MaybeUninits and drop all initialized elements in case of a panic. Miri complains about undefined behaviour, which I've reduced to the example below.

use std::mem::{transmute, MaybeUninit};

fn main() {
    unsafe {
        let mut item: MaybeUninit<String> = MaybeUninit::uninit();
        let ptr = item.as_mut_ptr();
        item = MaybeUninit::new(String::from("Hello"));
        println!("{}", transmute::<_, &String>(&item));
        ptr.drop_in_place();
    }
}

Error message produced by cargo miri run:

error: Undefined Behavior: trying to reborrow for SharedReadWrite at alloc1336, but parent tag <untagged> does not have an appropriate item in the borrow stack
   --> /home/antek/.local/opt/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:179:1
    |
179 | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to reborrow for SharedReadWrite at alloc1336, but parent tag <untagged> does not have an appropriate item in the borrow stack
    |

As far as I can tell, this is exactly how MaybeUninit is supposed to be used. Am I using the interface incorrectly and invoking undefined behaviour, or is Miri being overly conservative?

Upvotes: 3

Views: 485

Answers (1)

Aplet123
Aplet123

Reputation: 35550

Your issue is actually completely unrelated to MaybeUninit and can be boiled down to:

fn main() {
    let mut item = 0;
    let ptr = &item as *const _;
    item = 1;
    // or do anything with the pointer
    unsafe { &*ptr; }
}

Playground link Which throws the same "undefined behavior" error when run with Miri. From what I could gather by reading their reference, it seems like Miri has some metadata that keeps track of which pointers are allowed to read an item, and when you reassign that item, the metadata is wiped. However, reassigning values shouldn't change their memory address, so I would say that this is a bug with Miri and not UB.

In fact, changing ptr to a *mut i32 then using ptr.write instead of the assignment actually gets rid of the UB warning, which means it's probably a false positive.

Upvotes: 3

Related Questions