about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-16 12:40:53 +0000
committerbors <bors@rust-lang.org>2024-04-16 12:40:53 +0000
commitfee494b2b283c4cdcc816b2723fc8d9ee6e0dedd (patch)
tree341afdf8b56705a6e8c2a84d380deb030bb0aaf3 /src/tools
parent1129faca2bc7287b777fc45637cd0ba5364368a9 (diff)
parent811d4de5a01348a47fc747796094a593b7e6bb73 (diff)
downloadrust-fee494b2b283c4cdcc816b2723fc8d9ee6e0dedd.tar.gz
rust-fee494b2b283c4cdcc816b2723fc8d9ee6e0dedd.zip
Auto merge of #3472 - RalfJung:deadlock, r=RalfJung
deadlock: show backtrace for all threads

Fixes https://github.com/rust-lang/miri/issues/3424
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs2
-rw-r--r--src/tools/miri/src/concurrency/thread.rs5
-rw-r--r--src/tools/miri/src/diagnostics.rs70
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr23
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr24
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr21
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr21
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs1
-rw-r--r--src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr21
-rw-r--r--src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr4
-rw-r--r--src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr4
15 files changed, 175 insertions, 25 deletions
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index aa99a14b18e..5a941ae9d03 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -438,7 +438,7 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
             .machine
             .threads
             .all_stacks()
-            .flatten()
+            .flat_map(|(_id, stack)| stack)
             .map(|frame| {
                 frame.extra.borrow_tracker.as_ref().expect("we should have borrow tracking data")
             })
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 06e23188332..e28e5f83697 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -445,11 +445,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
     ) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>> {
         &mut self.threads[self.active_thread].stack
     }
-
     pub fn all_stacks(
         &self,
-    ) -> impl Iterator<Item = &[Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>]> {
-        self.threads.iter().map(|t| &t.stack[..])
+    ) -> impl Iterator<Item = (ThreadId, &[Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>])> {
+        self.threads.iter_enumerated().map(|(id, t)| (id, &t.stack[..]))
     }
 
     /// Create a new thread and returns its id.
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 30349c003a9..dfbcaaac5c6 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -361,9 +361,12 @@ pub fn report_error<'tcx, 'mir>(
     };
 
     let stacktrace = ecx.generate_stacktrace();
-    let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
+    let (stacktrace, mut any_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
 
-    // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
+    let mut show_all_threads = false;
+
+    // We want to dump the allocation if this is `InvalidUninitBytes`.
+    // Since `format_interp_error` consumes `e`, we compute the outut early.
     let mut extra = String::new();
     match e.kind() {
         UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
@@ -375,6 +378,15 @@ pub fn report_error<'tcx, 'mir>(
             .unwrap();
             writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
         }
+        MachineStop(info) => {
+            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
+            match info {
+                TerminationInfo::Deadlock => {
+                    show_all_threads = true;
+                }
+                _ => {}
+            }
+        }
         _ => {}
     }
 
@@ -387,18 +399,39 @@ pub fn report_error<'tcx, 'mir>(
         vec![],
         helps,
         &stacktrace,
+        Some(ecx.get_active_thread()),
         &ecx.machine,
     );
 
+    eprint!("{extra}"); // newlines are already in the string
+
+    if show_all_threads {
+        for (thread, stack) in ecx.machine.threads.all_stacks() {
+            if thread != ecx.get_active_thread() {
+                let stacktrace = Frame::generate_stacktrace_from_stack(stack);
+                let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
+                any_pruned |= was_pruned;
+                report_msg(
+                    DiagLevel::Error,
+                    format!("deadlock: the evaluated program deadlocked"),
+                    vec![format!("the evaluated program deadlocked")],
+                    vec![],
+                    vec![],
+                    &stacktrace,
+                    Some(thread),
+                    &ecx.machine,
+                )
+            }
+        }
+    }
+
     // Include a note like `std` does when we omit frames from a backtrace
-    if was_pruned {
+    if any_pruned {
         ecx.tcx.dcx().note(
             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
         );
     }
 
-    eprint!("{extra}"); // newlines are already in the string
-
     // Debug-dump all locals.
     for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
         trace!("-------------------");
@@ -435,6 +468,7 @@ pub fn report_leaks<'mir, 'tcx>(
             vec![],
             vec![],
             &backtrace,
+            None, // we don't know the thread this is from
             &ecx.machine,
         );
     }
@@ -457,6 +491,7 @@ pub fn report_msg<'tcx>(
     notes: Vec<(Option<SpanData>, String)>,
     helps: Vec<(Option<SpanData>, String)>,
     stacktrace: &[FrameInfo<'tcx>],
+    thread: Option<ThreadId>,
     machine: &MiriMachine<'_, 'tcx>,
 ) {
     let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
@@ -506,12 +541,13 @@ pub fn report_msg<'tcx>(
     if extra_span {
         write!(backtrace_title, " (of the first span)").unwrap();
     }
-    let thread_name =
-        machine.threads.get_thread_display_name(machine.threads.get_active_thread_id());
-    if thread_name != "main" {
-        // Only print thread name if it is not `main`.
-        write!(backtrace_title, " on thread `{thread_name}`").unwrap();
-    };
+    if let Some(thread) = thread {
+        let thread_name = machine.threads.get_thread_display_name(thread);
+        if thread_name != "main" {
+            // Only print thread name if it is not `main`.
+            write!(backtrace_title, " on thread `{thread_name}`").unwrap();
+        };
+    }
     write!(backtrace_title, ":").unwrap();
     err.note(backtrace_title);
     for (idx, frame_info) in stacktrace.iter().enumerate() {
@@ -628,7 +664,16 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             _ => vec![],
         };
 
-        report_msg(diag_level, title, vec![msg], notes, helps, &stacktrace, self);
+        report_msg(
+            diag_level,
+            title,
+            vec![msg],
+            notes,
+            helps,
+            &stacktrace,
+            Some(self.threads.get_active_thread_id()),
+            self,
+        );
     }
 }
 
@@ -654,6 +699,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             vec![],
             vec![],
             &stacktrace,
+            Some(this.get_active_thread()),
             &this.machine,
         );
     }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
index 910e06222ee..532bda20136 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
@@ -1,6 +1,7 @@
 //@only-target-windows: Uses win32 api functions
 // We are making scheduler assumptions here.
 //@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
 
 // On windows, joining main is not UB, but it will block a thread forever.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
index d9137ee7437..12f35fdeb02 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
@@ -8,7 +8,28 @@ LL |             assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJ
    = note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
+   |                                                                                          ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> $DIR/windows_join_main.rs:LL:CC
+   |
+LL | /     thread::spawn(|| {
+LL | |         unsafe {
+LL | |             assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0);
+LL | |         }
+LL | |     })
+LL | |     .join()
+   | |___________^
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
index a7c8faf5a98..a64265ca0ca 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
@@ -1,6 +1,7 @@
 //@only-target-windows: Uses win32 api functions
 // We are making scheduler assumptions here.
 //@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
 
 // On windows, a thread joining itself is not UB, but it will deadlock.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
index 74699a0317f..8d26c35de8a 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
@@ -7,7 +7,29 @@ LL |             assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0
    = note: BACKTRACE on thread `unnamed-ID`:
    = note: inside closure at $DIR/windows_join_self.rs:LL:CC
 
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
+   |                                                                                          ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> $DIR/windows_join_self.rs:LL:CC
+   |
+LL | /     thread::spawn(|| {
+LL | |         unsafe {
+LL | |             let native = GetCurrentThread();
+LL | |             assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0);
+LL | |         }
+LL | |     })
+LL | |     .join()
+   | |___________^
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs
index 6c3cb738e29..60d56d41fd9 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs
@@ -1,4 +1,5 @@
 //@ignore-target-windows: No libc on Windows
+//@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr
index 76b1d26bd33..987d0fc4c2d 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr
@@ -7,7 +7,26 @@ LL |             assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _
    = note: BACKTRACE on thread `unnamed-ID`:
    = note: inside closure at $DIR/libc_pthread_mutex_deadlock.rs:LL:CC
 
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC
+   |
+LL | /         thread::spawn(move || {
+LL | |             assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0);
+LL | |         })
+LL | |         .join()
+   | |_______________^
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs
index 201844615e1..0f02c3231a6 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs
@@ -1,4 +1,5 @@
 //@ignore-target-windows: No libc on Windows
+//@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr
index 5501dab81ac..bc9b15f293e 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr
@@ -7,7 +7,26 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
    = note: BACKTRACE on thread `unnamed-ID`:
    = note: inside closure at $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
 
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
+   |
+LL | /         thread::spawn(move || {
+LL | |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
+LL | |         })
+LL | |         .join()
+   | |_______________^
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs
index b1d7e0492e5..10be5b33752 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs
@@ -1,4 +1,5 @@
 //@ignore-target-windows: No libc on Windows
+//@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr
index 815d85af502..66c142bbc5c 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr
@@ -7,7 +7,26 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
    = note: BACKTRACE on thread `unnamed-ID`:
    = note: inside closure at $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
 
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
+   |
+LL | /         thread::spawn(move || {
+LL | |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0);
+LL | |         })
+LL | |         .join()
+   | |_______________^
+
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
index cca17a07ec2..960cae90124 100644
--- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
+++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
@@ -15,13 +15,13 @@ note: inside `main`
 LL |         drop(slice1.cmp(slice2));
    |              ^^^^^^^^^^^^^^^^^^
 
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
 Uninitialized memory occurred at ALLOC[0x4..0x10], in this allocation:
 ALLOC (Rust heap, size: 32, align: 8) {
     0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░
     0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░
 }
 
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
index 4dc2d27ead4..5439418f267 100644
--- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
+++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
@@ -15,8 +15,6 @@ note: inside `main`
 LL |         drop(slice1.cmp(slice2));
    |              ^^^^^^^^^^^^^^^^^^
 
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
 Uninitialized memory occurred at ALLOC[0x4..0x8], in this allocation:
 ALLOC (Rust heap, size: 16, align: 8) {
     ╾42[ALLOC]<TAG> (1 ptr byte)╼ 12 13 ╾43[ALLOC]<TAG> (1 ptr byte)╼ __ __ __ __ __ __ __ __ __ __ __ __ │ ━..━░░░░░░░░░░░░
@@ -28,5 +26,7 @@ ALLOC (global (static or const), size: 1, align: 1) {
     00                                              │ .
 }
 
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
 error: aborting due to 1 previous error