Hi everybody,
I am trying to write a custom smart pointer, and I need to call the destructor of a type (T) before the rest of the struct (S) in which it is. However, that struct (S) is accessed by a NonNull pointer only.. The type T and the type O, the type which is calling the destructor of T, both have this NonNull.
Specifically, the destructor of T looks at the data in S. However, this should not raise an error in Miri because NonNull<S< is not dropped or deallocated yet - only the destructor of a member of S (T) has been called.
I have attached a minimum reproducable code - as well as the full Miri traceback.
Code:
use std::{ptr::NonNull, mem::{ManuallyDrop, MaybeUninit}};
struct Wrapper<T> {
x: String,
v: T,
}
struct Outer {
i: NonNull<Wrapper<Inner>>,
}
struct Inner {
i: NonNull<Wrapper<Inner>>,
}
impl Drop for Inner {
fn drop(&mut self) {
println!("{}", unsafe { self.i.as_ref() }.x);
}
}
fn main() {
let wrapper_uninit = NonNull::from(Box::leak(Box::from(Wrapper {
x: String::from("HELLO"),
v: MaybeUninit::<Inner>::uninit()
})));
let wrapper_ptr = wrapper_uninit.cast::<Wrapper<Inner>>();
let inner = Inner {
i: wrapper_ptr
};
let ptr = wrapper_ptr.as_ptr();
unsafe { std::ptr::write(std::ptr::addr_of_mut!((*ptr).v), inner) };
let mut data = NonNull::from(Box::leak(Box::from(Outer {
i: wrapper_ptr
})));
unsafe { std::ptr::drop_in_place(&mut data.as_mut().i.as_mut().v as *mut _) };
unsafe { std::ptr::drop_in_place(&mut data.as_mut().i.as_mut().x as *mut _) };
unsafe { Box::from_raw(data.as_ref().i.as_ptr().cast::<ManuallyDrop<Outer>>()) };
unsafe { Box::from_raw(data.as_ptr().cast::<ManuallyDrop<Outer>>()) };
}
Miri traceback:
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `/home/ericbuehler/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/miri_err`
error: Undefined Behavior: not granting access to tag <2840> because that would remove [Unique for <3026>] which is strongly protected because it is an argument of call 810
--> /home/ericbuehler/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:376:18
|
376 | unsafe { &*self.as_ptr() }
| ^^^^^^^^^^^^^^^ not granting access to tag <2840> because that would remove [Unique for <3026>] which is strongly protected because it is an argument of call 810
|
= 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: <2840> was created by a SharedReadWrite retag at offsets [0x0..0x20]
--> src/main.rs:23:26
|
23 | let wrapper_uninit = NonNull::from(Box::leak(Box::from(Wrapper {
| __________________________^
24 | | x: String::from("HELLO"),
25 | | v: MaybeUninit::<Inner>::uninit()
26 | | })));
| |________^
help: <3026> is this argument
--> src/main.rs:40:14
|
40 | unsafe { std::ptr::drop_in_place(&mut data.as_mut().i.as_mut().v as *mut _) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `std::ptr::NonNull::<Wrapper<Inner>>::as_ref::<'_>` at /home/ericbuehler/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:376:18: 376:33
note: inside `<Inner as std::ops::Drop>::drop`
--> src/main.rs:18:33
|
18 | println!("{}", unsafe { self.i.as_ref() }.x);
| ^^^^^^^^^^^^^^^
= note: inside `std::ptr::drop_in_place::<Inner> - shim(Some(Inner))` at /home/ericbuehler/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:497:1: 497:56
note: inside `main`
--> src/main.rs:40:14
|
40 | unsafe { std::ptr::drop_in_place(&mut data.as_mut().i.as_mut().v as *mut _) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error
To install and use Miri:
rustup +nightly component add miri
cargo +nightly miri run