add test for close-while-blocked

This commit is contained in:
Ralf Jung 2024-12-27 12:18:09 +01:00
parent 16cffc7275
commit 75209df948
3 changed files with 78 additions and 8 deletions

View file

@ -167,10 +167,9 @@ fn anonsocket_write<'tcx>(
dest: MPlaceTy<'tcx>,
}
@unblock = |this| {
let Some(self_ref) = weak_self_ref.upgrade() else {
// FIXME: We should raise a deadlock error if the self_ref upgrade failed.
throw_unsup_format!("This will be a deadlock error in future")
};
// If we got unblocked, then our peer successfully upgraded its weak
// ref to us. That means we can also upgrade our weak ref.
let self_ref = weak_self_ref.upgrade().unwrap();
anonsocket_write(&self_ref, ptr, len, &dest, this)
}
),
@ -257,10 +256,9 @@ fn anonsocket_read<'tcx>(
dest: MPlaceTy<'tcx>,
}
@unblock = |this| {
let Some(self_ref) = weak_self_ref.upgrade() else {
// FIXME: We should raise a deadlock error if the self_ref upgrade failed.
throw_unsup_format!("This will be a deadlock error in future")
};
// If we got unblocked, then our peer successfully upgraded its weak
// ref to us. That means we can also upgrade our weak ref.
let self_ref = weak_self_ref.upgrade().unwrap();
anonsocket_read(&self_ref, len, ptr, &dest, this)
}
),

View file

@ -0,0 +1,37 @@
//! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
//! faulty logic around `release_clock` that led to this code not reporting a data race.
//~^^ERROR: deadlock
//@ignore-target: windows # no libc socketpair on Windows
//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
//@error-in-other-file: deadlock
use std::thread;
fn main() {
let mut fds = [-1, -1];
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
assert_eq!(res, 0);
let thread1 = thread::spawn(move || {
let mut buf: [u8; 1] = [0; 1];
let _res: i32 = unsafe {
libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) //~ERROR: deadlock
.try_into()
.unwrap()
};
});
let thread2 = thread::spawn(move || {
// Close the FD that the other thread is blocked on.
unsafe { libc::close(fds[1]) };
});
// Run the other threads.
thread::yield_now();
// When they are both done, continue here.
let data = "a".as_bytes().as_ptr();
let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 1) };
assert_eq!(res, -1);
thread1.join().unwrap();
thread2.join().unwrap();
}

View file

@ -0,0 +1,35 @@
error: deadlock: the evaluated program deadlocked
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
LL | let ret = unsafe { libc::pthread_join(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`
--> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
|
LL | thread1.join().unwrap();
| ^^^^^^^^^^^^^^
error: deadlock: the evaluated program deadlocked
--> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
|
LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
| ^ the evaluated program deadlocked
|
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside closure at tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
error: deadlock: the evaluated program deadlocked
|
= note: the evaluated program deadlocked
= note: (no span available)
= note: BACKTRACE on thread `unnamed-ID`:
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 3 previous errors