about summary refs log tree commit diff
path: root/src/tools/miri/tests
diff options
context:
space:
mode:
authorOli Scherer <github35764891676564198441@oli-obk.de>2024-12-18 19:23:42 +0000
committerGitHub <noreply@github.com>2024-12-18 19:23:42 +0000
commit4ce3b85ce564c7cb33b7a3339c95bf07c2764005 (patch)
treeb2f959501089d5a320007c6dee3926b57212d851 /src/tools/miri/tests
parent955ef0983112c6a10c54457cedc38eedefcdefb9 (diff)
parent1f771300002f69b03807f26b47fc6ff1a68a9b14 (diff)
downloadrust-4ce3b85ce564c7cb33b7a3339c95bf07c2764005.tar.gz
rust-4ce3b85ce564c7cb33b7a3339c95bf07c2764005.zip
Merge pull request #4072 from tiif/blockop
Implement blocking unnamed_socket
Diffstat (limited to 'src/tools/miri/tests')
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs47
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs49
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs12
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr5
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs16
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr5
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs50
9 files changed, 232 insertions, 34 deletions
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
new file mode 100644
index 00000000000..d3e4c43f2b7
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
@@ -0,0 +1,47 @@
+//@ignore-target: windows # No libc socketpair on Windows
+//~^ERROR: deadlocked
+//~^^ERROR: deadlocked
+// test_race depends on a deterministic schedule.
+//@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
+
+use std::thread;
+
+// Test the behaviour of a thread being blocked on read, get unblocked, then blocked again.
+
+// The expected execution is
+// 1. Thread 1 blocks.
+// 2. Thread 2 blocks.
+// 3. Thread 3 unblocks both thread 1 and thread 2.
+// 4. Thread 1 reads.
+// 5. Thread 2's `read` can never complete -> deadlocked.
+
+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 this thread block on read.
+        let mut buf: [u8; 3] = [0; 3];
+        let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+        assert_eq!(res, 3);
+        assert_eq!(&buf, "abc".as_bytes());
+    });
+    let thread2 = thread::spawn(move || {
+        // Let this thread block on read.
+        let mut buf: [u8; 3] = [0; 3];
+        let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+        //~^ERROR: deadlocked
+        assert_eq!(res, 3);
+        assert_eq!(&buf, "abc".as_bytes());
+    });
+    let thread3 = thread::spawn(move || {
+        // Unblock thread1 by writing something.
+        let data = "abc".as_bytes().as_ptr();
+        let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+        assert_eq!(res, 3);
+    });
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
new file mode 100644
index 00000000000..ab807a579db
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
@@ -0,0 +1,41 @@
+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_block_read_twice.rs:LL:CC
+   |
+LL |     thread2.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/socketpair_block_read_twice.rs:LL:CC
+   |
+LL |         let res = unsafe { 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_block_read_twice.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 4 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
new file mode 100644
index 00000000000..4f951acb2c3
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
@@ -0,0 +1,49 @@
+//@ignore-target: windows # No libc socketpair on Windows
+//~^ERROR: deadlocked
+//~^^ERROR: deadlocked
+// test_race depends on a deterministic schedule.
+//@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
+
+use std::thread;
+
+// Test the behaviour of a thread being blocked on write, get unblocked, then blocked again.
+
+// The expected execution is
+// 1. Thread 1 blocks.
+// 2. Thread 2 blocks.
+// 3. Thread 3 unblocks both thread 1 and thread 2.
+// 4. Thread 1 reads.
+// 5. Thread 2's `write` can never complete -> deadlocked.
+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 arr1: [u8; 212992] = [1; 212992];
+    // Exhaust the space in the buffer so the subsequent write will block.
+    let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
+    assert_eq!(res, 212992);
+    let thread1 = thread::spawn(move || {
+        let data = "abc".as_bytes().as_ptr();
+        // The write below will be blocked because the buffer is already full.
+        let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+        assert_eq!(res, 3);
+    });
+    let thread2 = thread::spawn(move || {
+        let data = "abc".as_bytes().as_ptr();
+        // The write below will be blocked because the buffer is already full.
+        let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+        //~^ERROR: deadlocked
+        assert_eq!(res, 3);
+    });
+    let thread3 = thread::spawn(move || {
+        // Unblock thread1 by freeing up some space.
+        let mut buf: [u8; 3] = [0; 3];
+        let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+        assert_eq!(res, 3);
+        assert_eq!(buf, [1, 1, 1]);
+    });
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
new file mode 100644
index 00000000000..44cda11102d
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
@@ -0,0 +1,41 @@
+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_block_write_twice.rs:LL:CC
+   |
+LL |     thread2.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/socketpair_block_write_twice.rs:LL:CC
+   |
+LL |         let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+   |                                                                              ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/socketpair_block_write_twice.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 4 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs
deleted file mode 100644
index ffa4e36f0f4..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ignore-target: windows # no libc socketpair on Windows
-
-// This is temporarily here because blocking on fd is not supported yet.
-// When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair
-
-fn main() {
-    let mut fds = [-1, -1];
-    let _ = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
-    // The read below will be blocked because the buffer is empty.
-    let mut buf: [u8; 3] = [0; 3];
-    let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) }; //~ERROR: blocking isn't supported
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr
index 16892614c63..caf23da1150 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_read_blocking.stderr
@@ -1,10 +1,9 @@
-error: unsupported operation: socketpair/pipe/pipe2 read: blocking isn't supported yet
+error: deadlock: the evaluated program deadlocked
   --> tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC
    |
 LL |     let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 read: blocking isn't supported yet
+   |                                                                                              ^ the evaluated program deadlocked
    |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs
deleted file mode 100644
index e83197dfc0f..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ignore-target: windows # no libc socketpair on Windows
-// This is temporarily here because blocking on fd is not supported yet.
-// When blocking is eventually supported, this will be moved to pass-dep/libc/libc-socketpair
-fn main() {
-    let mut fds = [-1, -1];
-    let _ = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
-    // Write size > buffer capacity
-    // Used up all the space in the buffer.
-    let arr1: [u8; 212992] = [1; 212992];
-    let _ = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
-    let data = "abc".as_bytes().as_ptr();
-    // The write below will be blocked as the buffer is full.
-    let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) }; //~ERROR: blocking isn't supported
-    let mut buf: [u8; 3] = [0; 3];
-    let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr
index a2fcf87578a..2dc420d5f1e 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_write_blocking.stderr
@@ -1,10 +1,9 @@
-error: unsupported operation: socketpair/pipe/pipe2 write: blocking isn't supported yet
+error: deadlock: the evaluated program deadlocked
   --> tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC
    |
 LL |     let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 write: blocking isn't supported yet
+   |                                                                        ^ the evaluated program deadlocked
    |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
index 64819e57679..bbf0e215953 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
@@ -10,6 +10,8 @@ fn main() {
     test_socketpair();
     test_socketpair_threaded();
     test_race();
+    test_blocking_read();
+    test_blocking_write();
 }
 
 fn test_socketpair() {
@@ -136,3 +138,51 @@ fn test_race() {
     thread::yield_now();
     thread1.join().unwrap();
 }
+
+// Test the behaviour of a socketpair getting blocked on read and subsequently unblocked.
+fn test_blocking_read() {
+    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 this thread block on read.
+        let mut buf: [u8; 3] = [0; 3];
+        let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+        assert_eq!(res, 3);
+        assert_eq!(&buf, "abc".as_bytes());
+    });
+    let thread2 = thread::spawn(move || {
+        // Unblock thread1 by doing writing something.
+        let data = "abc".as_bytes().as_ptr();
+        let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+        assert_eq!(res, 3);
+    });
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+}
+
+// Test the behaviour of a socketpair getting blocked on write and subsequently unblocked.
+fn test_blocking_write() {
+    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 arr1: [u8; 212992] = [1; 212992];
+    // Exhaust the space in the buffer so the subsequent write will block.
+    let res = unsafe { libc::write(fds[0], arr1.as_ptr() as *const libc::c_void, 212992) };
+    assert_eq!(res, 212992);
+    let thread1 = thread::spawn(move || {
+        let data = "abc".as_bytes().as_ptr();
+        // The write below will be blocked because the buffer is already full.
+        let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
+        assert_eq!(res, 3);
+    });
+    let thread2 = thread::spawn(move || {
+        // Unblock thread1 by freeing up some space.
+        let mut buf: [u8; 3] = [0; 3];
+        let res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+        assert_eq!(res, 3);
+        assert_eq!(buf, [1, 1, 1]);
+    });
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+}