Skip to content

Commit

Permalink
Add tests for for the re-block path
Browse files Browse the repository at this point in the history
  • Loading branch information
tiif committed Dec 13, 2024
1 parent 6d9d5dd commit 1a48b03
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
48 changes: 48 additions & 0 deletions tests/fail-dep/libc/socketpair_block_read_twice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//@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 an socketpair::read, get unblocked, and then
// get 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 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();
thread3.join().unwrap();
}
41 changes: 41 additions & 0 deletions tests/fail-dep/libc/socketpair_block_read_twice.stderr
Original file line number Diff line number Diff line change
@@ -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

50 changes: 50 additions & 0 deletions tests/fail-dep/libc/socketpair_block_write_twice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//@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 an socketpair::write, get unblocked, and then
// get 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();
}
41 changes: 41 additions & 0 deletions tests/fail-dep/libc/socketpair_block_write_twice.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 1a48b03

Please sign in to comment.