diff options
| author | Oli Scherer <github35764891676564198441@oli-obk.de> | 2024-12-18 19:23:42 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-18 19:23:42 +0000 |
| commit | 4ce3b85ce564c7cb33b7a3339c95bf07c2764005 (patch) | |
| tree | b2f959501089d5a320007c6dee3926b57212d851 /src/tools/miri/tests | |
| parent | 955ef0983112c6a10c54457cedc38eedefcdefb9 (diff) | |
| parent | 1f771300002f69b03807f26b47fc6ff1a68a9b14 (diff) | |
| download | rust-4ce3b85ce564c7cb33b7a3339c95bf07c2764005.tar.gz rust-4ce3b85ce564c7cb33b7a3339c95bf07c2764005.zip | |
Merge pull request #4072 from tiif/blockop
Implement blocking unnamed_socket
Diffstat (limited to 'src/tools/miri/tests')
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(); +} |
