Skip to content

Conversation

@joboet
Copy link
Member

@joboet joboet commented Nov 7, 2025

The documentation for Condvar::wait currently states that

This function may panic! if it is used with more than one mutex over time.

This is however only true on UNIX platforms that still use the pthread Condvar implementation (namely macOS, some BSDs like NetBSDs and some very niche platforms like VxWorks), making it likely that users will not be aware of this caveat.

Hence in this PR, I've modified the pthread-based implementation to allow multi-mutex-use by adding an inner mutex that bridges the gap between the unlock operation on the user-specified mutex and the actual condvar wait.

Note that this closes the door on making the futex-based notify_all() a requeuing operation, as the waiters might not be sharing the same mutex. At the same time, the implementation change here makes it easier to switch the Mutex implementation independent of the Condvar one, which would e.g. simplify switching it to employ os_unfair_lock on macOS.

@rustbot label +I-libs-nominated

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Nov 7, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 7, 2025

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the I-libs-nominated Nominated for discussion during a libs team meeting. label Nov 7, 2025
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-miri failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
tests/pass/tls/tls_macro_drop.rs (revision `stack`) ... ok
tests/pass/tls/tls_macro_drop.rs (revision `tree`) ... ok

FAILED TEST: tests/pass/tree_borrows/read_retag_no_race.rs
command: MIRI_ENV_VAR_TEST="0" MIRI_TEMP="/tmp/miri-uitest-czW0AS" RUST_BACKTRACE="1" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/miri" "--error-format=json" "--sysroot=/checkout/obj/build/x86_64-unknown-linux-gnu/miri-sysroot" "-Dwarnings" "-Dunused" "-Ainternal_features" "-Zui-testing" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/tmp/miri_ui/0/tests/pass/tree_borrows" "tests/pass/tree_borrows/read_retag_no_race.rs" "-Zmiri-tree-borrows" "-Zmiri-deterministic-concurrency" "--edition" "2021" "--target" "aarch64-apple-darwin"

error: test got exit status: 1, but expected 0
 = note: compilation failed, but was expected to succeed

error: actual output differed from expected
Execute `./miri test --bless` to update `tests/pass/tree_borrows/read_retag_no_race.stderr` to the actual output
--- tests/pass/tree_borrows/read_retag_no_race.stderr
+++ <stderr output>
 Thread 1 executing: spawn
 Thread 2 executing: spawn
 Thread 2 executing: read x || retag y
-Thread 1 executing: read x || retag y
-Thread 1 executing: write y
-Thread 2 executing: write y
-Thread 2 executing: exit
-Thread 1 executing: exit
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   |
+LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
+   |                                                             ^ this thread got stuck here
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside `std::sys::pal::PLATFORM::sync::mutex::Mutex::lock` at RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Mutex::lock` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `<std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at RUSTLIB/core/src/mem/drop_guard.rs:LL:CC
+   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Condvar::wait` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::Barrier::wait` at RUSTLIB/std/src/sync/barrier.rs:LL:CC
+note: inside `thread_1`
+  --> tests/pass/tree_borrows/read_retag_no_race.rs:LL:CC
+   |
+LL |         barrier.wait();
+   |         ^^^^^^^^^^^^^^
+...
+LL |     synchronized!(barrier, "spawn");
+   |     ------------------------------- in this macro invocation
+note: inside closure
+  --> tests/pass/tree_borrows/read_retag_no_race.rs:LL:CC
+   |
+LL |     let h1 = thread::spawn(move || thread_1(p, b1));
+   |                                    ^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ this thread got stuck here
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.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
---
+
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   |
+LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
+   |                                                             ^ this thread got stuck here
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside `std::sys::pal::PLATFORM::sync::mutex::Mutex::lock` at RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::State::lock` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Condvar::wait` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::Barrier::wait` at RUSTLIB/std/src/sync/barrier.rs:LL:CC
+note: inside `thread_2`
+  --> tests/pass/tree_borrows/read_retag_no_race.rs:LL:CC
+   |
+LL |         barrier.wait();
+   |         ^^^^^^^^^^^^^^
+...
+LL |     synchronized!(barrier, "read x || retag y");
+   |     ------------------------------------------- in this macro invocation
+note: inside closure
+  --> tests/pass/tree_borrows/read_retag_no_race.rs:LL:CC
+   |
+LL |     let h2 = thread::spawn(move || thread_2(p, b2));
+   |                                    ^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 3 previous errors
+

Full unnormalized output:
Thread 1 executing: spawn
Thread 2 executing: spawn
Thread 2 executing: read x || retag y
error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-1`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::mutex::pthread::Mutex::lock` at /checkout/library/std/src/sys/sync/mutex/pthread.rs:36:18: 36:35
   = note: inside closure at /checkout/library/std/src/sys/sync/condvar/pthread.rs:125:53: 125:65
   = note: inside `<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at /checkout/library/core/src/mem/drop_guard.rs:142:9: 142:17
   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>))` at /checkout/library/core/src/ptr/mod.rs:805:1: 807:25
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:132:5: 132:6
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside `thread_1`
  --> tests/pass/tree_borrows/read_retag_no_race.rs:65:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |     synchronized!(barrier, "spawn");
   |     ------------------------------- in this macro invocation
note: inside closure
  --> tests/pass/tree_borrows/read_retag_no_race.rs:110:36
   |
LL |     let h1 = thread::spawn(move || thread_1(p, b1));
   |                                    ^^^^^^^^^^^^^^^
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/thread/unix.rs:132:66
   |
LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
   |                                                                  ^ this thread got stuck here
   |
   = note: BACKTRACE:
   = note: inside `std::sys::thread::unix::Thread::join` at /checkout/library/std/src/sys/thread/unix.rs:132:66: 132:67
   = note: inside `std::thread::JoinInner::<'_, ()>::join` at /checkout/library/std/src/thread/mod.rs:1808:9: 1808:27
   = note: inside `std::thread::JoinHandle::<()>::join` at /checkout/library/std/src/thread/mod.rs:1963:9: 1963:22
---

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-2`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::condvar::pthread::State::lock` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:43:18: 43:30
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:118:30: 118:42
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside `thread_2`
  --> tests/pass/tree_borrows/read_retag_no_race.rs:65:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |     synchronized!(barrier, "read x || retag y");
   |     ------------------------------------------- in this macro invocation
note: inside closure
  --> tests/pass/tree_borrows/read_retag_no_race.rs:111:36
   |
LL |     let h2 = thread::spawn(move || thread_2(p, b2));
   |                                    ^^^^^^^^^^^^^^^
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

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

error: aborting due to 3 previous errors



full stderr:
Thread 1 executing: spawn
Thread 2 executing: spawn
Thread 2 executing: read x || retag y
error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-1`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::mutex::pthread::Mutex::lock` at /checkout/library/std/src/sys/sync/mutex/pthread.rs:36:18: 36:35
   = note: inside closure at /checkout/library/std/src/sys/sync/condvar/pthread.rs:125:53: 125:65
   = note: inside `<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at /checkout/library/core/src/mem/drop_guard.rs:142:9: 142:17
   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>))` at /checkout/library/core/src/ptr/mod.rs:805:1: 807:25
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:132:5: 132:6
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside `thread_1`
  --> tests/pass/tree_borrows/read_retag_no_race.rs:65:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |     synchronized!(barrier, "spawn");
   |     ------------------------------- in this macro invocation
note: inside closure
  --> tests/pass/tree_borrows/read_retag_no_race.rs:110:36
   |
LL |     let h1 = thread::spawn(move || thread_1(p, b1));
   |                                    ^^^^^^^^^^^^^^^
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/thread/unix.rs:132:66
   |
LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
   |                                                                  ^ this thread got stuck here
   |
   = note: BACKTRACE:
   = note: inside `std::sys::thread::unix::Thread::join` at /checkout/library/std/src/sys/thread/unix.rs:132:66: 132:67
   = note: inside `std::thread::JoinInner::<'_, ()>::join` at /checkout/library/std/src/thread/mod.rs:1808:9: 1808:27
   = note: inside `std::thread::JoinHandle::<()>::join` at /checkout/library/std/src/thread/mod.rs:1963:9: 1963:22
---

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-2`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::condvar::pthread::State::lock` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:43:18: 43:30
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:118:30: 118:42
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside `thread_2`
  --> tests/pass/tree_borrows/read_retag_no_race.rs:65:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |     synchronized!(barrier, "read x || retag y");
   |     ------------------------------------------- in this macro invocation
note: inside closure
  --> tests/pass/tree_borrows/read_retag_no_race.rs:111:36
   |
LL |     let h2 = thread::spawn(move || thread_2(p, b2));
   |                                    ^^^^^^^^^^^^^^^
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

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

---



FAILED TEST: tests/pass/tree_borrows/spurious_read.rs
command: MIRI_ENV_VAR_TEST="0" MIRI_TEMP="/tmp/miri-uitest-czW0AS" RUST_BACKTRACE="1" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/miri" "--error-format=json" "--sysroot=/checkout/obj/build/x86_64-unknown-linux-gnu/miri-sysroot" "-Dwarnings" "-Dunused" "-Ainternal_features" "-Zui-testing" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/tmp/miri_ui/0/tests/pass/tree_borrows" "tests/pass/tree_borrows/spurious_read.rs" "-Zmiri-deterministic-concurrency" "-Zmiri-tree-borrows" "--edition" "2021" "--target" "aarch64-apple-darwin"

error: test got exit status: 1, but expected 0
 = note: compilation failed, but was expected to succeed

error: actual output differed from expected
Execute `./miri test --bless` to update `tests/pass/tree_borrows/spurious_read.stderr` to the actual output
--- tests/pass/tree_borrows/spurious_read.stderr
+++ <stderr output>
 Thread 1 executing: start
 Thread 2 executing: start
 Thread 2 executing: retag x (&mut, protect)
-Thread 1 executing: retag x (&mut, protect)
-Thread 1 executing: retag y (&mut, protect)
-Thread 2 executing: retag y (&mut, protect)
-Thread 2 executing: spurious read x
-Thread 1 executing: spurious read x
-Thread 1 executing: ret x
-Thread 2 executing: ret x
-Thread 2 executing: ret y
-Thread 1 executing: ret y
-Thread 1 executing: write y
-Thread 2 executing: write y
-Thread 2 executing: end
-Thread 1 executing: end
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   |
+LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
+   |                                                             ^ this thread got stuck here
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside `std::sys::pal::PLATFORM::sync::mutex::Mutex::lock` at RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Mutex::lock` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `<std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at RUSTLIB/core/src/mem/drop_guard.rs:LL:CC
+   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::PLATFORM::pthread::Mutex, {closure@std::sys::sync::PLATFORM::pthread::Condvar::wait::{closure#0}}>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Condvar::wait` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::Barrier::wait` at RUSTLIB/std/src/sync/barrier.rs:LL:CC
+note: inside closure
+  --> tests/pass/tree_borrows/spurious_read.rs:LL:CC
+   |
+LL |         barrier.wait();
+   |         ^^^^^^^^^^^^^^
+...
+LL |         synchronized!(b, "start");
+   |         ------------------------- in this macro invocation
+   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ this thread got stuck here
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.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 `retagx_retagy_spuriousx_retx_rety_writey`
+  --> tests/pass/tree_borrows/spurious_read.rs:LL:CC
+   |
+LL |     thread_x.join().unwrap();
+   |     ^^^^^^^^^^^^^^^
+note: inside `main`
+  --> tests/pass/tree_borrows/spurious_read.rs:LL:CC
+   |
+LL |     retagx_retagy_spuriousx_retx_rety_writey();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   |
+LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
+   |                                                             ^ this thread got stuck here
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside `std::sys::pal::PLATFORM::sync::mutex::Mutex::lock` at RUSTLIB/std/src/sys/pal/PLATFORM/sync/mutex.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::State::lock` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sys::sync::PLATFORM::pthread::Condvar::wait` at RUSTLIB/std/src/sys/sync/PLATFORM/pthread.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at RUSTLIB/std/src/sync/nonpoison/condvar.rs:LL:CC
+   = note: inside `std::sync::Barrier::wait` at RUSTLIB/std/src/sync/barrier.rs:LL:CC
+note: inside closure
+  --> tests/pass/tree_borrows/spurious_read.rs:LL:CC
+   |
+LL |         barrier.wait();
+   |         ^^^^^^^^^^^^^^
+...
+LL |         synchronized!(b, "retag x (&mut, protect)");
+   |         ------------------------------------------- in this macro invocation
+   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 3 previous errors
+

Full unnormalized output:
Thread 1 executing: start
Thread 2 executing: start
Thread 2 executing: retag x (&mut, protect)
error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-1`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::mutex::pthread::Mutex::lock` at /checkout/library/std/src/sys/sync/mutex/pthread.rs:36:18: 36:35
   = note: inside closure at /checkout/library/std/src/sys/sync/condvar/pthread.rs:125:53: 125:65
   = note: inside `<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at /checkout/library/core/src/mem/drop_guard.rs:142:9: 142:17
   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>))` at /checkout/library/core/src/ptr/mod.rs:805:1: 807:25
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:132:5: 132:6
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside closure
  --> tests/pass/tree_borrows/spurious_read.rs:34:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |         synchronized!(b, "start");
   |         ------------------------- in this macro invocation
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/thread/unix.rs:132:66
   |
LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
   |                                                                  ^ this thread got stuck here
   |
   = note: BACKTRACE:
   = note: inside `std::sys::thread::unix::Thread::join` at /checkout/library/std/src/sys/thread/unix.rs:132:66: 132:67
   = note: inside `std::thread::JoinInner::<'_, ()>::join` at /checkout/library/std/src/thread/mod.rs:1808:9: 1808:27
   = note: inside `std::thread::JoinHandle::<()>::join` at /checkout/library/std/src/thread/mod.rs:1963:9: 1963:22
note: inside `retagx_retagy_spuriousx_retx_rety_writey`
  --> tests/pass/tree_borrows/spurious_read.rs:113:5
   |
LL |     thread_x.join().unwrap();
   |     ^^^^^^^^^^^^^^^
note: inside `main`
  --> tests/pass/tree_borrows/spurious_read.rs:20:5
   |
LL |     retagx_retagy_spuriousx_retx_rety_writey();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-2`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::condvar::pthread::State::lock` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:43:18: 43:30
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:118:30: 118:42
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside closure
  --> tests/pass/tree_borrows/spurious_read.rs:34:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |         synchronized!(b, "retag x (&mut, protect)");
   |         ------------------------------------------- in this macro invocation
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

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

error: aborting due to 3 previous errors



full stderr:
Thread 1 executing: start
Thread 2 executing: start
Thread 2 executing: retag x (&mut, protect)
error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-1`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::mutex::pthread::Mutex::lock` at /checkout/library/std/src/sys/sync/mutex/pthread.rs:36:18: 36:35
   = note: inside closure at /checkout/library/std/src/sys/sync/condvar/pthread.rs:125:53: 125:65
   = note: inside `<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}> as std::ops::Drop>::drop` at /checkout/library/core/src/mem/drop_guard.rs:142:9: 142:17
   = note: inside `std::ptr::drop_in_place::<std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>> - shim(Some(std::mem::DropGuard<&std::sys::sync::mutex::pthread::Mutex, {closure@std::sys::sync::condvar::pthread::Condvar::wait::{closure#0}}>))` at /checkout/library/core/src/ptr/mod.rs:805:1: 807:25
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:132:5: 132:6
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside closure
  --> tests/pass/tree_borrows/spurious_read.rs:34:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |         synchronized!(b, "start");
   |         ------------------------- in this macro invocation
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/thread/unix.rs:132:66
   |
LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
   |                                                                  ^ this thread got stuck here
   |
   = note: BACKTRACE:
   = note: inside `std::sys::thread::unix::Thread::join` at /checkout/library/std/src/sys/thread/unix.rs:132:66: 132:67
   = note: inside `std::thread::JoinInner::<'_, ()>::join` at /checkout/library/std/src/thread/mod.rs:1808:9: 1808:27
   = note: inside `std::thread::JoinHandle::<()>::join` at /checkout/library/std/src/thread/mod.rs:1963:9: 1963:22
note: inside `retagx_retagy_spuriousx_retx_rety_writey`
  --> tests/pass/tree_borrows/spurious_read.rs:113:5
   |
LL |     thread_x.join().unwrap();
   |     ^^^^^^^^^^^^^^^
note: inside `main`
  --> tests/pass/tree_borrows/spurious_read.rs:20:5
   |
LL |     retagx_retagy_spuriousx_retx_rety_writey();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: the evaluated program deadlocked
##[error]  --> /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61
   |
LL |         let r = unsafe { libc::pthread_mutex_lock(self.raw()) };
   |                                                             ^ this thread got stuck here
   |
   = note: BACKTRACE on thread `unnamed-2`:
   = note: inside `std::sys::pal::unix::sync::mutex::Mutex::lock` at /checkout/library/std/src/sys/pal/unix/sync/mutex.rs:72:61: 72:62
   = note: inside `std::sys::sync::condvar::pthread::State::lock` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:43:18: 43:30
   = note: inside `std::sys::sync::condvar::pthread::Condvar::wait` at /checkout/library/std/src/sys/sync/condvar/pthread.rs:118:30: 118:42
   = note: inside `std::sync::nonpoison::Condvar::wait::<std::sync::barrier::BarrierState>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:121:13: 121:34
   = note: inside `std::sync::nonpoison::Condvar::wait_while::<std::sync::barrier::BarrierState, {closure@std::sync::Barrier::wait::{closure#0}}>` at /checkout/library/std/src/sync/nonpoison/condvar.rs:174:13: 174:29
   = note: inside `std::sync::Barrier::wait` at /checkout/library/std/src/sync/barrier.rs:128:13: 128:86
note: inside closure
  --> tests/pass/tree_borrows/spurious_read.rs:34:9
   |
LL |         barrier.wait();
   |         ^^^^^^^^^^^^^^
...
LL |         synchronized!(b, "retag x (&mut, protect)");
   |         ------------------------------------------- in this macro invocation
   = note: this error originates in the macro `synchronized` (in Nightly builds, run with -Z macro-backtrace for more info)

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

---
Location:
   /cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ui_test-0.30.2/src/lib.rs:365

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   1: <color_eyre[1f5202221233abbe]::config::EyreHook>::into_eyre_hook::{closure#0}<unknown>
      at <unknown source file>:<unknown line>
   2: eyre[48df789685eb06cc]::private::format_err<unknown>
      at <unknown source file>:<unknown line>
   3: ui_test[bc52f6833025c4e0]::run_tests_generic::<ui_test[bc52f6833025c4e0]::default_file_filter, ui[7d63d8c9c1866ff1]::run_tests::{closure#1}, alloc[de0088778f4ca588]::boxed::Box<dyn ui_test[bc52f6833025c4e0]::status_emitter::StatusEmitter>><unknown>
      at <unknown source file>:<unknown line>
   4: ui[7d63d8c9c1866ff1]::ui<unknown>
      at <unknown source file>:<unknown line>
   5: ui[7d63d8c9c1866ff1]::main<unknown>
      at <unknown source file>:<unknown line>
   6: std[e622a49bc3cbdaa4]::sys::backtrace::__rust_begin_short_backtrace::<fn() -> core[b2f1ee12dab5c3dd]::result::Result<(), eyre[48df789685eb06cc]::Report>, core[b2f1ee12dab5c3dd]::result::Result<(), eyre[48df789685eb06cc]::Report>><unknown>
      at <unknown source file>:<unknown line>
   7: std[e622a49bc3cbdaa4]::rt::lang_start::<core[b2f1ee12dab5c3dd]::result::Result<(), eyre[48df789685eb06cc]::Report>>::{closure#0}<unknown>
      at <unknown source file>:<unknown line>
   8: std[e622a49bc3cbdaa4]::rt::lang_start_internal<unknown>
      at <unknown source file>:<unknown line>
   9: main<unknown>
      at <unknown source file>:<unknown line>
  10: __libc_start_main<unknown>
      at <unknown source file>:<unknown line>
  11: _start<unknown>
      at <unknown source file>:<unknown line>

Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering.
Run with RUST_BACKTRACE=full to include source snippets.
error: test failed, to rerun pass `--test ui`

Caused by:
  process didn't exit successfully: `/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/release/deps/ui-60d430e8ea50df4d` (exit status: 1)
Bootstrap failed while executing `test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target aarch64-apple-darwin`
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo test --target x86_64-unknown-linux-gnu -Zbinary-dep-depinfo -j 4 -Zroot-dir=/checkout --locked --color always --release --manifest-path /checkout/src/tools/miri/Cargo.toml -- [workdir=/checkout]` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:191:21
Executed at: src/bootstrap/src/core/build_steps/test.rs:676:19

Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:01:46
  local time: Fri Nov  7 16:47:43 UTC 2025
  network time: Fri, 07 Nov 2025 16:47:43 GMT
##[error]Process completed with exit code 1.
##[group]Run echo "disk usage:"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-libs-nominated Nominated for discussion during a libs team meeting. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants