about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-12-27 12:18:09 +0100
committerRalf Jung <post@ralfj.de>2024-12-27 12:18:09 +0100
commit75209df94842750f58afac0646349c1318bac478 (patch)
tree4e07fc88b5f0b54b6002b62a91afdbb93d37fd1a
parent16cffc727557145d83ccd32f6f727270ed3816af (diff)
downloadrust-75209df94842750f58afac0646349c1318bac478.tar.gz
rust-75209df94842750f58afac0646349c1318bac478.zip
add test for close-while-blocked
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs14
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs37
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr35
3 files changed, 78 insertions, 8 deletions
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 7f35838e9d7..4285786f063 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -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)
                     }
                 ),
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
new file mode 100644
index 00000000000..8413e118819
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
@@ -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();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
new file mode 100644
index 00000000000..fe196f5d7d7
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
@@ -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
+