about summary refs log tree commit diff
path: root/src/tools/miri/tests
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-08-16 22:34:50 +0200
committerRalf Jung <post@ralfj.de>2024-08-17 11:32:17 +0200
commit99d742e9b0b7191543567faa67a04c65a4d1bcaf (patch)
tree1fe5f90afde2a40369d7f3df2b0cb8487c6e9ab6 /src/tools/miri/tests
parent78dfb8a10870689491c89db55baf1cc4688cb972 (diff)
downloadrust-99d742e9b0b7191543567faa67a04c65a4d1bcaf.tar.gz
rust-99d742e9b0b7191543567faa67a04c65a4d1bcaf.zip
implement pipe and pipe2
Diffstat (limited to 'src/tools/miri/tests')
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-pipe.rs106
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs20
2 files changed, 120 insertions, 6 deletions
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
new file mode 100644
index 00000000000..a57cad124b6
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
@@ -0,0 +1,106 @@
+//@ignore-target-windows: No libc pipe on Windows
+// test_race depends on a deterministic schedule.
+//@compile-flags: -Zmiri-preemption-rate=0
+use std::thread;
+fn main() {
+    test_pipe();
+    test_pipe_threaded();
+    test_race();
+}
+
+fn test_pipe() {
+    let mut fds = [-1, -1];
+    let mut res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    // Read size == data available in buffer.
+    let data = "12345".as_bytes().as_ptr();
+    res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5).try_into().unwrap() };
+    assert_eq!(res, 5);
+    let mut buf3: [u8; 5] = [0; 5];
+    res = unsafe {
+        libc::read(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t).try_into().unwrap()
+    };
+    assert_eq!(res, 5);
+    assert_eq!(buf3, "12345".as_bytes());
+
+    // Read size > data available in buffer.
+    let data = "123".as_bytes().as_ptr();
+    res = unsafe { libc::write(fds[1], data as *const libc::c_void, 3).try_into().unwrap() };
+    assert_eq!(res, 3);
+    let mut buf4: [u8; 5] = [0; 5];
+    res = unsafe {
+        libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t).try_into().unwrap()
+    };
+    assert_eq!(res, 3);
+    assert_eq!(&buf4[0..3], "123".as_bytes());
+}
+
+fn test_pipe_threaded() {
+    let mut fds = [-1, -1];
+    let mut res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    let thread1 = thread::spawn(move || {
+        let mut buf: [u8; 5] = [0; 5];
+        let res: i64 = unsafe {
+            libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+                .try_into()
+                .unwrap()
+        };
+        assert_eq!(res, 5);
+        assert_eq!(buf, "abcde".as_bytes());
+    });
+    // FIXME: we should yield here once blocking is implemented.
+    //thread::yield_now();
+    let data = "abcde".as_bytes().as_ptr();
+    res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5).try_into().unwrap() };
+    assert_eq!(res, 5);
+    thread1.join().unwrap();
+
+    // Read and write from different direction
+    let thread2 = thread::spawn(move || {
+        // FIXME: we should yield here once blocking is implemented.
+        //thread::yield_now();
+        let data = "12345".as_bytes().as_ptr();
+        let res: i64 =
+            unsafe { libc::write(fds[1], data as *const libc::c_void, 5).try_into().unwrap() };
+        assert_eq!(res, 5);
+    });
+    // FIXME: we should not yield here once blocking is implemented.
+    thread::yield_now();
+    let mut buf: [u8; 5] = [0; 5];
+    res = unsafe {
+        libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap()
+    };
+    assert_eq!(res, 5);
+    assert_eq!(buf, "12345".as_bytes());
+    thread2.join().unwrap();
+}
+
+fn test_race() {
+    static mut VAL: u8 = 0;
+    let mut fds = [-1, -1];
+    let mut res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+    let thread1 = thread::spawn(move || {
+        let mut buf: [u8; 1] = [0; 1];
+        // write() from the main thread will occur before the read() here
+        // because preemption is disabled and the main thread yields after write().
+        let res: i32 = unsafe {
+            libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+                .try_into()
+                .unwrap()
+        };
+        assert_eq!(res, 1);
+        assert_eq!(buf, "a".as_bytes());
+        // The read above establishes a happens-before so it is now safe to access this global variable.
+        unsafe { assert_eq!(VAL, 1) };
+    });
+    unsafe { VAL = 1 };
+    let data = "a".as_bytes().as_ptr();
+    res = unsafe { libc::write(fds[1], data as *const libc::c_void, 1).try_into().unwrap() };
+    assert_eq!(res, 1);
+    thread::yield_now();
+    thread1.join().unwrap();
+}
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 324c0127ee9..254be89d482 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
@@ -66,9 +66,6 @@ fn test_socketpair_threaded() {
         unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
     assert_eq!(res, 0);
 
-    let data = "abcde".as_bytes().as_ptr();
-    res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5).try_into().unwrap() };
-    assert_eq!(res, 5);
     let thread1 = thread::spawn(move || {
         let mut buf: [u8; 5] = [0; 5];
         let res: i64 = unsafe {
@@ -79,23 +76,33 @@ fn test_socketpair_threaded() {
         assert_eq!(res, 5);
         assert_eq!(buf, "abcde".as_bytes());
     });
+    // FIXME: we should yield here once blocking is implemented.
+    //thread::yield_now();
+    let data = "abcde".as_bytes().as_ptr();
+    res = unsafe { libc::write(fds[0], data as *const libc::c_void, 5).try_into().unwrap() };
+    assert_eq!(res, 5);
     thread1.join().unwrap();
 
     // Read and write from different direction
     let thread2 = thread::spawn(move || {
+        // FIXME: we should yield here once blocking is implemented.
+        //thread::yield_now();
         let data = "12345".as_bytes().as_ptr();
         let res: i64 =
-            unsafe { libc::write(fds[0], data as *const libc::c_void, 5).try_into().unwrap() };
+            unsafe { libc::write(fds[1], data as *const libc::c_void, 5).try_into().unwrap() };
         assert_eq!(res, 5);
     });
-    thread2.join().unwrap();
+    // FIXME: we should not yield here once blocking is implemented.
+    thread::yield_now();
     let mut buf: [u8; 5] = [0; 5];
     res = unsafe {
-        libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap()
+        libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap()
     };
     assert_eq!(res, 5);
     assert_eq!(buf, "12345".as_bytes());
+    thread2.join().unwrap();
 }
+
 fn test_race() {
     static mut VAL: u8 = 0;
     let mut fds = [-1, -1];
@@ -113,6 +120,7 @@ fn test_race() {
         };
         assert_eq!(res, 1);
         assert_eq!(buf, "a".as_bytes());
+        // The read above establishes a happens-before so it is now safe to access this global variable.
         unsafe { assert_eq!(VAL, 1) };
     });
     unsafe { VAL = 1 };