Skip to content

ICE using -Zmiri-tag-raw-pointers: 'we should never pop more than one frame at once' #2081

@BennoLossin

Description

@BennoLossin

I tried this code (havent tried to reduce this yet, because i discovered this while trying to solve another bug):

Code
#![deny(unsafe_op_in_unsafe_fn)]
use core::{
    marker::PhantomPinned,
    mem::{self, ManuallyDrop, MaybeUninit},
    pin::Pin,
    ptr::{addr_of, addr_of_mut},
};

#[repr(transparent)]
struct UnsafeAliasCell<T> {
    value: T,
    _pin: PhantomPinned,
}

impl<T> UnsafeAliasCell<T> {
    pub fn new(value: T) -> Self {
        Self {
            value,
            _pin: PhantomPinned,
        }
    }

    pub fn get(&mut self) -> *mut T {
        addr_of_mut!(self.value)
    }
}

#[repr(C)]
pub struct PtrBufUninit<T, const N: usize> {
    idx: MaybeUninit<*const T>,
    end: MaybeUninit<*const T>,
    buf: UnsafeAliasCell<[ManuallyDrop<T>; N]>,
}

struct PtrBufUninitProj<'pin, T, const N: usize> {
    idx: &'pin mut MaybeUninit<*const T>,
    end: &'pin mut MaybeUninit<*const T>,
    buf: &'pin mut UnsafeAliasCell<[ManuallyDrop<T>; N]>,
}

#[repr(C)]
pub struct PtrBuf<T, const N: usize> {
    idx: *const T,
    end: *const T,
    buf: UnsafeAliasCell<[ManuallyDrop<T>; N]>,
}

struct PtrBufProj<'pin, T, const N: usize> {
    idx: &'pin mut *const T,
    end: &'pin mut *const T,
    #[allow(dead_code)]
    buf: &'pin mut UnsafeAliasCell<[ManuallyDrop<T>; N]>,
}

impl<T, const N: usize> PtrBufUninit<T, N> {
    pub fn init(mut self: Pin<Box<Self>>) -> Pin<Box<PtrBuf<T, N>>> {
        let this = self.as_mut().project();
        let ptr = this.buf.get() as *const T;
        this.idx.write(ptr);
        let ptr = unsafe {
            //ptr.offset(N as isize - 1)
            // SAFETY: buf is a valid pointer
            addr_of!((*(this.buf.get() as *mut [ManuallyDrop<T>; N]))[N - 1])
                as *const ManuallyDrop<T> as *const T
        };
        this.end.write(ptr);
        unsafe {
            // SAFETY: we do not move the contents of the box
            let this = Pin::into_inner_unchecked(self);
            let this = Box::from_raw(Box::into_raw(this) as *mut PtrBuf<T, N>);
            Pin::new_unchecked(this)
        }
    }

    fn project(self: Pin<&mut Self>) -> PtrBufUninitProj<'_, T, N> {
        // SAFETY: we do not structually pin anything, we only need buf to stay where it is.
        let this = unsafe { Pin::get_unchecked_mut(self) };
        PtrBufUninitProj {
            idx: &mut this.idx,
            end: &mut this.end,
            buf: &mut this.buf,
        }
    }
}

impl<T, const N: usize> PtrBuf<T, N> {
    fn project(self: Pin<&mut Self>) -> PtrBufProj<'_, T, N> {
        // SAFETY: we do not structually pin anything, we only need buf to stay where it is.
        let this = unsafe { Pin::get_unchecked_mut(self) };
        PtrBufProj {
            idx: &mut this.idx,
            end: &mut this.end,
            buf: &mut this.buf,
        }
    }
}

impl<T, const N: usize> From<[T; N]> for PtrBufUninit<T, N> {
    fn from(arr: [T; N]) -> Self {
        assert_ne!(N, 0);
        assert!(
            N < isize::MAX as usize,
            "N cannot be bigger than isize::MAX"
        );
        Self {
            idx: MaybeUninit::uninit(),
            end: MaybeUninit::uninit(),
            buf: unsafe {
                // SAFETY: T and ManuallyDrop<T> have the same layout, so [T; N] and
                // [ManuallyDrop<T>; N] also have the same layout
                let ptr = addr_of!(arr) as *const [T; N] as *const [ManuallyDrop<T>; N];
                mem::forget(arr);
                UnsafeAliasCell::new(ptr.read())
            },
        }
    }
}

impl<T, const N: usize> PtrBuf<T, N> {
    pub fn next(self: Pin<&mut Self>) -> Option<T> {
        let this = self.project();
        if this.idx > this.end {
            None
        } else {
            let val = unsafe {
                // SAFETY: we checked if idx is in bounds before and
                // we read the value at idx and offset idx, this value is never read again
                this.idx.read()
            };
            unsafe {
                // SAFETY: we are still in bounds of buf (end stores the end of buf)
                // and adding size_of::<T>() will only land us at most one byte of buf.
                *this.idx = this.idx.offset(1);
            }
            Some(val)
        }
    }
}

impl<T, const N: usize> Drop for PtrBuf<T, N> {
    fn drop(&mut self) {
        fn pinned_drop<T, const N: usize>(mut this: Pin<&mut PtrBuf<T, N>>) {
            while let Some(x) = this.as_mut().next() {
                drop(x);
            }
        }
        pinned_drop(unsafe { Pin::new_unchecked(self) });
    }
}

impl<T, const N: usize> Drop for PtrBufUninit<T, N> {
    fn drop(&mut self) {
        let slice = unsafe {
            // We did not access buf anywhere yet
            &mut *self.buf.get()
        };
        for x in slice {
            unsafe {
                // SAFETY: we are dropping ourselves and thus this is subject to the same
                // invariants
                ManuallyDrop::drop(x);
            }
        }
    }
}

fn main() {
    let buf: PtrBufUninit<i32, 5> = [42, -42, 1337, 0, 6].into();
    let mut buf = Box::pin(buf).init();
    assert_eq!(buf.as_mut().next(), Some(42));
    assert_eq!(buf.as_mut().next(), Some(-42));
    assert_eq!(buf.as_mut().next(), Some(1337));
    assert_eq!(buf.as_mut().next(), Some(0));
    assert_eq!(buf.as_mut().next(), Some(6));
    assert_eq!(buf.as_mut().next(), None);
}
Then when running under miri with
MIRIFLAGS="-Zmiri-tag-raw-pointers -Zmiri-track-pointer-tag=2500" cargo miri run
Stacktrace
note: tracking was triggered
   --> ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/maybe_uninit.rs:634:13
    |
634 |             ManuallyDrop::into_inner(self.value)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ created tag 2500
    |
    = note: inside `std::mem::MaybeUninit::<[std::mem::ManuallyDrop<i32>; 5]>::assume_init` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/maybe_uninit.rs:634:13
    = note: inside `std::ptr::read::<[std::mem::ManuallyDrop<i32>; 5]>` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1097:9
    = note: inside `std::ptr::const_ptr::<impl *const [std::mem::ManuallyDrop<i32>; 5]>::read` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:941:18
note: inside `<PtrBufUninit<i32, 5_usize> as std::convert::From<[i32; 5]>>::from` at src/main.rs:113:38
   --> src/main.rs:113:38
    |
113 |                 UnsafeAliasCell::new(ptr.read())
    |                                      ^^^^^^^^^^
    = note: inside `<[i32; 5] as std::convert::Into<PtrBufUninit<i32, 5_usize>>>::into` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:550:9
note: inside `main` at src/main.rs:168:37
   --> src/main.rs:168:37
    |
168 |     let buf: PtrBufUninit<i32, 5> = [42, -42, 1337, 0, 6].into();
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

thread 'rustc' panicked at 'we should never pop more than one frame at once', src/tools/miri/src/diagnostics.rs:377:17
stack backtrace:
   0:     0x7f4767bec85d - std::backtrace_rs::backtrace::libunwind::trace::hd79e9b51bb0b02a3
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x7f4767bec85d - std::backtrace_rs::backtrace::trace_unsynchronized::hc4b2624d11f57391
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x7f4767bec85d - std::sys_common::backtrace::_print_fmt::h5b920b6df28041d5
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys_common/backtrace.rs:66:5
   3:     0x7f4767bec85d - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h01f2db48eea34166
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys_common/backtrace.rs:45:22
   4:     0x7f4767c47efc - core::fmt::write::h743b8fce003c331c
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/core/src/fmt/mod.rs:1194:17
   5:     0x7f4767bde041 - std::io::Write::write_fmt::h55edc38b905db9b5
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/io/mod.rs:1655:15
   6:     0x7f4767bef575 - std::sys_common::backtrace::_print::h72c54a6b7a86b7bf
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys_common/backtrace.rs:48:5
   7:     0x7f4767bef575 - std::sys_common::backtrace::print::h8b541992f5fa33c9
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys_common/backtrace.rs:35:9
   8:     0x7f4767bef575 - std::panicking::default_hook::{{closure}}::h47e8a61e5844dea4
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/panicking.rs:295:22
   9:     0x7f4767bef1e9 - std::panicking::default_hook::h65ae1796882c178c
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/panicking.rs:314:9
  10:     0x7f476838d5a1 - rustc_driver[caca827775d68846]::DEFAULT_HOOK::{closure#0}::{closure#0}
  11:     0x7f4767befd46 - std::panicking::rust_panic_with_hook::h1c3eee211b989bad
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/panicking.rs:702:17
  12:     0x7f4767befb09 - std::panicking::begin_panic_handler::{{closure}}::h653627205f5b2cdc
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/panicking.rs:586:13
  13:     0x7f4767becd14 - std::sys_common::backtrace::__rust_end_short_backtrace::h36d845a914b6aae7
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys_common/backtrace.rs:138:18
  14:     0x7f4767bef879 - rust_begin_unwind
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/panicking.rs:584:5
  15:     0x7f4767bb4bd3 - core::panicking::panic_fmt::hb6389d787a80a806
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/core/src/panicking.rs:142:14
  16:     0x5646cd103156 - <std[fd2a1eaf3e081d4d]::thread::local::LocalKey<core[864d7ae58f623181]::cell::RefCell<alloc[642b2cd0ec1e1a81]::vec::Vec<miri[11bda64e92b8a89f]::diagnostics::NonHaltingDiagnostic>>>>::with::<<rustc_const_eval[ec16a9026af29337]::interpret::eval_context::InterpCx<miri[11bda64e92b8a89f]::machine::Evaluator> as miri[11bda64e92b8a89f]::diagnostics::EvalContextExt>::process_diagnostics::{closure#0}, ()>
  17:     0x5646cd0f7159 - miri[11bda64e92b8a89f]::eval::eval_entry
  18:     0x5646cd06a902 - <rustc_interface[dacacaf3651fe347]::passes::QueryContext>::enter::<<miri[aaa733ecb7479b45]::MiriCompilerCalls as rustc_driver[caca827775d68846]::Callbacks>::after_analysis::{closure#0}, ()>
  19:     0x5646cd06346e - <miri[aaa733ecb7479b45]::MiriCompilerCalls as rustc_driver[caca827775d68846]::Callbacks>::after_analysis
  20:     0x7f476a3a1ab5 - <rustc_interface[dacacaf3651fe347]::interface::Compiler>::enter::<rustc_driver[caca827775d68846]::run_compiler::{closure#1}::{closure#2}, core[864d7ae58f623181]::result::Result<core[864d7ae58f623181]::option::Option<rustc_interface[dacacaf3651fe347]::queries::Linker>, rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>
  21:     0x7f476a3cb3ff - rustc_span[ff646084812721ee]::with_source_map::<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_interface[dacacaf3651fe347]::interface::create_compiler_and_run<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_driver[caca827775d68846]::run_compiler::{closure#1}>::{closure#1}>
  22:     0x7f476a3b5d64 - rustc_interface[dacacaf3651fe347]::interface::create_compiler_and_run::<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_driver[caca827775d68846]::run_compiler::{closure#1}>
  23:     0x7f476a39efa1 - <scoped_tls[d6203f3b3010b98e]::ScopedKey<rustc_span[ff646084812721ee]::SessionGlobals>>::set::<rustc_interface[dacacaf3651fe347]::interface::run_compiler<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_driver[caca827775d68846]::run_compiler::{closure#1}>::{closure#0}, core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>
  24:     0x7f476a3b854f - std[fd2a1eaf3e081d4d]::sys_common::backtrace::__rust_begin_short_backtrace::<rustc_interface[dacacaf3651fe347]::util::run_in_thread_pool_with_globals<rustc_interface[dacacaf3651fe347]::interface::run_compiler<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_driver[caca827775d68846]::run_compiler::{closure#1}>::{closure#0}, core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>::{closure#0}, core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>
  25:     0x7f476a3b8689 - <<std[fd2a1eaf3e081d4d]::thread::Builder>::spawn_unchecked_<rustc_interface[dacacaf3651fe347]::util::run_in_thread_pool_with_globals<rustc_interface[dacacaf3651fe347]::interface::run_compiler<core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>, rustc_driver[caca827775d68846]::run_compiler::{closure#1}>::{closure#0}, core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>::{closure#0}, core[864d7ae58f623181]::result::Result<(), rustc_errors[14f27e81a88a2c7]::ErrorGuaranteed>>::{closure#1} as core[864d7ae58f623181]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  26:     0x7f4767bf9bf3 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::h211dae6d8dec3611
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/alloc/src/boxed.rs:1866:9
  27:     0x7f4767bf9bf3 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::hb54334e8a7bb1f12
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/alloc/src/boxed.rs:1866:9
  28:     0x7f4767bf9bf3 - std::sys::unix::thread::Thread::new::thread_start::hf8b57655f2f2e68e
                               at /rustc/4ca19e09d302a4cbde14f9cb1bc109179dc824cd/library/std/src/sys/unix/thread.rs:108:17
  29:     0x7f47678b6b1a - start_thread
  30:     0x7f476793b660 - __GI___clone3
  31:                0x0 - <unknown>

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.62.0-nightly (4ca19e09d 2022-04-19) running on x86_64-unknown-linux-gnu

note: compiler flags: --crate-type bin -C embed-bitcode=no -C debuginfo=2 -C incremental -Z miri-tag-raw-pointers -Z miri-track-pointer-tag=2500

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack

It also occures on the current master branch (3ac7ca4).

Removing the -Zmiri-track-raw-pointers produces no ICE.

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