about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-05 14:07:43 +0000
committerbors <bors@rust-lang.org>2024-05-05 14:07:43 +0000
commit19a5d475f26b76c013de6190e854bc65afac6f28 (patch)
tree92c0ac3a85cc80c0b7e3dda016ea49eab444c62f
parente1b5e5540f7b63393ad78c913c55dcf70333ee10 (diff)
parentf3018409fc85dcf4ef95a1f97915b010796d1afe (diff)
downloadrust-19a5d475f26b76c013de6190e854bc65afac6f28.tar.gz
rust-19a5d475f26b76c013de6190e854bc65afac6f28.zip
Auto merge of #3565 - RalfJung:libc, r=RalfJung
re-organize libc tests

And share some more things across unices
-rwxr-xr-xsrc/tools/miri/ci/ci.sh10
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs20
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs28
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs8
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-fs.rs174
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs13
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-getrandom-without-isolation.rs41
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-misc.rs365
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-random.rs (renamed from src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs)26
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-time.rs93
-rw-r--r--src/tools/miri/tests/pass-dep/shims/posix_memalign.rs82
-rw-r--r--src/tools/miri/tests/pass/hello.rs1
-rw-r--r--src/tools/miri/tests/pass/hello.stderr1
14 files changed, 418 insertions, 451 deletions
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 03a387d43c7..713c97830a5 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -143,12 +143,12 @@ case $HOST_TARGET in
     # Partially supported targets (tier 2)
     VERY_BASIC="integer vec string btreemap" # common things we test on all of them (if they have std), requires no target-specific shims
     BASIC="$VERY_BASIC hello hashmap alloc align" # ensures we have the shims for stdout and basic data structures
-    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus
-    MIRI_TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-getentropy libc-getrandom libc-misc fs env num_cpus
-    MIRI_TEST_TARGET=aarch64-linux-android  run_tests_minimal $VERY_BASIC hello panic/panic
-    MIRI_TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync
-	# TODO fix solaris stack guard
+    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus
+    MIRI_TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus
+    MIRI_TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync libc-misc libc-random
+    # TODO fix solaris stack guard
     # MIRI_TEST_TARGET=x86_64-pc-solaris run_tests_minimal $VERY_BASIC hello panic/panic pthread-sync
+    MIRI_TEST_TARGET=aarch64-linux-android  run_tests_minimal $VERY_BASIC hello panic/panic
     MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm
     MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm
     MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 45793602b21..595cf64a4e4 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -23,7 +23,7 @@ pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
         // well allow it in `dlsym`.
         "signal" => true,
         // needed at least on macOS to avoid file-based fallback in getrandom
-        "getentropy" => true,
+        "getentropy" | "getrandom" => true,
         // Give specific OSes a chance to allow their symbols.
         _ =>
             match target_os {
@@ -632,6 +632,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.write_scalar(Scalar::from_i32(0), dest)?;
                 }
             }
+            "getrandom" => {
+                // This function is non-standard but exists with the same signature and behavior on
+                // Linux, FreeBSD and Solaris/Illumos.
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris") {
+                    throw_unsup_format!(
+                        "`getentropy` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+                let [ptr, len, flags] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let ptr = this.read_pointer(ptr)?;
+                let len = this.read_target_usize(len)?;
+                let _flags = this.read_scalar(flags)?.to_i32()?;
+                // We ignore the flags, just always use the same PRNG / host RNG.
+                this.gen_random(ptr, len)?;
+                this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
+            }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 0d5d5cb3d9a..e70cd35dda6 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -20,11 +20,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
             // Threading
-            "pthread_attr_get_np" if this.frame_in_std() => {
-                let [_thread, _attr] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.write_null(dest)?;
-            }
             "pthread_set_name_np" => {
                 let [thread, name] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -75,27 +70,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             }
 
             // Miscellaneous
-            "getrandom" => {
-                let [ptr, len, flags] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let ptr = this.read_pointer(ptr)?;
-                let len = this.read_target_usize(len)?;
-                let _flags = this.read_scalar(flags)?.to_i32()?;
-                // flags on freebsd does not really matter
-                // in practice, GRND_RANDOM does not particularly draw from /dev/random
-                // since it is the same as to /dev/urandom.
-                // GRND_INSECURE is only an alias of GRND_NONBLOCK, which
-                // does not affect the RNG.
-                // https://man.freebsd.org/cgi/man.cgi?query=getrandom&sektion=2&n=1
-                this.gen_random(ptr, len)?;
-                this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
-            }
             "__error" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
+            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
+            // These shims are enabled only when the caller is in the standard library.
+            "pthread_attr_get_np" if this.frame_in_std() => {
+                let [_thread, _attr] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                this.write_null(dest)?;
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         }
         Ok(EmulateItemResult::NeedsJumping)
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 43b5db9e32d..ecf82f26a55 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -11,7 +11,7 @@ use shims::unix::linux::mem::EvalContextExt as _;
 use shims::unix::linux::sync::futex;
 
 pub fn is_dyn_sym(name: &str) -> bool {
-    matches!(name, "getrandom" | "statx")
+    matches!(name, "statx")
 }
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@@ -140,11 +140,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             }
 
             // Miscellaneous
-            "getrandom" => {
-                let [ptr, len, flags] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                getrandom(this, ptr, len, flags, dest)?;
-            }
             "mmap64" => {
                 let [addr, length, prot, flags, fd, offset] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index 16a04727561..c01ae0ecb90 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -10,7 +10,6 @@ pub fn is_dyn_sym(_name: &str) -> bool {
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    #[allow(warnings)]
     fn emulate_foreign_item_inner(
         &mut self,
         link_name: Symbol,
@@ -20,6 +19,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     ) -> InterpResult<'tcx, EmulateItemResult> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
+            // Miscellaneous
+            "___errno" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let errno_place = this.last_error_place()?;
+                this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         }
         Ok(EmulateItemResult::NeedsJumping)
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
index 4cfc1843a7a..0dd849a045d 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
@@ -4,10 +4,11 @@
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
 
-use std::ffi::CString;
+use std::ffi::{CStr, CString, OsString};
 use std::fs::{canonicalize, remove_dir_all, remove_file, File};
 use std::io::{Error, ErrorKind, Write};
 use std::os::unix::ffi::OsStrExt;
+use std::os::unix::io::AsRawFd;
 use std::path::PathBuf;
 
 #[path = "../../utils/mod.rs"]
@@ -27,6 +28,14 @@ fn main() {
     #[cfg(target_os = "linux")]
     test_o_tmpfile_flag();
     test_posix_mkstemp();
+    test_posix_realpath_alloc();
+    test_posix_realpath_noalloc();
+    test_posix_realpath_errors();
+    #[cfg(target_os = "linux")]
+    test_posix_fadvise();
+    #[cfg(target_os = "linux")]
+    test_sync_file_range();
+    test_isatty();
 }
 
 /// Prepare: compute filename and make sure the file does not exist.
@@ -256,3 +265,166 @@ fn test_posix_mkstemp() {
         assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
     }
 }
+
+/// Test allocating variant of `realpath`.
+fn test_posix_realpath_alloc() {
+    use std::os::unix::ffi::OsStrExt;
+    use std::os::unix::ffi::OsStringExt;
+
+    let buf;
+    let path = utils::tmp().join("miri_test_libc_posix_realpath_alloc");
+    let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
+
+    // Cleanup before test.
+    remove_file(&path).ok();
+    // Create file.
+    drop(File::create(&path).unwrap());
+    unsafe {
+        let r = libc::realpath(c_path.as_ptr(), std::ptr::null_mut());
+        assert!(!r.is_null());
+        buf = CStr::from_ptr(r).to_bytes().to_vec();
+        libc::free(r as *mut _);
+    }
+    let canonical = PathBuf::from(OsString::from_vec(buf));
+    assert_eq!(path.file_name(), canonical.file_name());
+
+    // Cleanup after test.
+    remove_file(&path).unwrap();
+}
+
+/// Test non-allocating variant of `realpath`.
+fn test_posix_realpath_noalloc() {
+    use std::ffi::{CStr, CString};
+    use std::os::unix::ffi::OsStrExt;
+
+    let path = utils::tmp().join("miri_test_libc_posix_realpath_noalloc");
+    let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
+
+    let mut v = vec![0; libc::PATH_MAX as usize];
+
+    // Cleanup before test.
+    remove_file(&path).ok();
+    // Create file.
+    drop(File::create(&path).unwrap());
+    unsafe {
+        let r = libc::realpath(c_path.as_ptr(), v.as_mut_ptr());
+        assert!(!r.is_null());
+    }
+    let c = unsafe { CStr::from_ptr(v.as_ptr()) };
+    let canonical = PathBuf::from(c.to_str().expect("CStr to str"));
+
+    assert_eq!(path.file_name(), canonical.file_name());
+
+    // Cleanup after test.
+    remove_file(&path).unwrap();
+}
+
+/// Test failure cases for `realpath`.
+fn test_posix_realpath_errors() {
+    use std::ffi::CString;
+    use std::io::ErrorKind;
+
+    // Test nonexistent path returns an error.
+    let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed");
+    let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) };
+    assert!(r.is_null());
+    let e = std::io::Error::last_os_error();
+    assert_eq!(e.raw_os_error(), Some(libc::ENOENT));
+    assert_eq!(e.kind(), ErrorKind::NotFound);
+}
+
+#[cfg(target_os = "linux")]
+fn test_posix_fadvise() {
+    use std::io::Write;
+
+    let path = utils::tmp().join("miri_test_libc_posix_fadvise.txt");
+    // Cleanup before test
+    remove_file(&path).ok();
+
+    // Set up an open file
+    let mut file = File::create(&path).unwrap();
+    let bytes = b"Hello, World!\n";
+    file.write(bytes).unwrap();
+
+    // Test calling posix_fadvise on a file.
+    let result = unsafe {
+        libc::posix_fadvise(
+            file.as_raw_fd(),
+            0,
+            bytes.len().try_into().unwrap(),
+            libc::POSIX_FADV_DONTNEED,
+        )
+    };
+    drop(file);
+    remove_file(&path).unwrap();
+    assert_eq!(result, 0);
+}
+
+#[cfg(target_os = "linux")]
+fn test_sync_file_range() {
+    use std::io::Write;
+
+    let path = utils::tmp().join("miri_test_libc_sync_file_range.txt");
+    // Cleanup before test.
+    remove_file(&path).ok();
+
+    // Write to a file.
+    let mut file = File::create(&path).unwrap();
+    let bytes = b"Hello, World!\n";
+    file.write(bytes).unwrap();
+
+    // Test calling sync_file_range on the file.
+    let result_1 = unsafe {
+        libc::sync_file_range(
+            file.as_raw_fd(),
+            0,
+            0,
+            libc::SYNC_FILE_RANGE_WAIT_BEFORE
+                | libc::SYNC_FILE_RANGE_WRITE
+                | libc::SYNC_FILE_RANGE_WAIT_AFTER,
+        )
+    };
+    drop(file);
+
+    // Test calling sync_file_range on a file opened for reading.
+    let file = File::open(&path).unwrap();
+    let result_2 = unsafe {
+        libc::sync_file_range(
+            file.as_raw_fd(),
+            0,
+            0,
+            libc::SYNC_FILE_RANGE_WAIT_BEFORE
+                | libc::SYNC_FILE_RANGE_WRITE
+                | libc::SYNC_FILE_RANGE_WAIT_AFTER,
+        )
+    };
+    drop(file);
+
+    remove_file(&path).unwrap();
+    assert_eq!(result_1, 0);
+    assert_eq!(result_2, 0);
+}
+
+fn test_isatty() {
+    // Testing whether our isatty shim returns the right value would require controlling whether
+    // these streams are actually TTYs, which is hard.
+    // For now, we just check that these calls are supported at all.
+    unsafe {
+        libc::isatty(libc::STDIN_FILENO);
+        libc::isatty(libc::STDOUT_FILENO);
+        libc::isatty(libc::STDERR_FILENO);
+
+        // But when we open a file, it is definitely not a TTY.
+        let path = utils::tmp().join("notatty.txt");
+        // Cleanup before test.
+        remove_file(&path).ok();
+        let file = File::create(&path).unwrap();
+
+        assert_eq!(libc::isatty(file.as_raw_fd()), 0);
+        assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOTTY);
+
+        // Cleanup after test.
+        drop(file);
+        remove_file(&path).unwrap();
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs b/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs
deleted file mode 100644
index 06109397c2b..00000000000
--- a/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ignore-target-windows: no libc
-
-use libc::getentropy;
-
-fn main() {
-    let mut buf1 = [0u8; 256];
-    let mut buf2 = [0u8; 257];
-    unsafe {
-        assert_eq!(getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
-        assert_eq!(getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
-        assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::EIO);
-    }
-}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-getrandom-without-isolation.rs b/src/tools/miri/tests/pass-dep/shims/libc-getrandom-without-isolation.rs
deleted file mode 100644
index 349b447569a..00000000000
--- a/src/tools/miri/tests/pass-dep/shims/libc-getrandom-without-isolation.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//@only-target-linux
-//@compile-flags: -Zmiri-disable-isolation
-
-use std::ptr;
-
-fn main() {
-    let mut buf = [0u8; 5];
-    unsafe {
-        assert_eq!(
-            libc::syscall(
-                libc::SYS_getrandom,
-                ptr::null_mut::<libc::c_void>(),
-                0 as libc::size_t,
-                0 as libc::c_uint,
-            ),
-            0,
-        );
-        assert_eq!(
-            libc::syscall(
-                libc::SYS_getrandom,
-                buf.as_mut_ptr() as *mut libc::c_void,
-                5 as libc::size_t,
-                0 as libc::c_uint,
-            ),
-            5,
-        );
-
-        assert_eq!(
-            libc::getrandom(ptr::null_mut::<libc::c_void>(), 0 as libc::size_t, 0 as libc::c_uint),
-            0,
-        );
-        assert_eq!(
-            libc::getrandom(
-                buf.as_mut_ptr() as *mut libc::c_void,
-                5 as libc::size_t,
-                0 as libc::c_uint,
-            ),
-            5,
-        );
-    }
-}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
index f710daf5277..9644920c499 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -1,158 +1,16 @@
 //@ignore-target-windows: No libc on Windows
 //@compile-flags: -Zmiri-disable-isolation
 #![feature(io_error_more)]
+#![feature(pointer_is_aligned_to)]
+#![feature(strict_provenance)]
 
-use std::fs::{remove_file, File};
-use std::mem::transmute;
-use std::os::unix::io::AsRawFd;
-use std::path::PathBuf;
-
-#[path = "../../utils/mod.rs"]
-mod utils;
-
-/// Test allocating variant of `realpath`.
-fn test_posix_realpath_alloc() {
-    use std::ffi::OsString;
-    use std::ffi::{CStr, CString};
-    use std::os::unix::ffi::OsStrExt;
-    use std::os::unix::ffi::OsStringExt;
-
-    let buf;
-    let path = utils::tmp().join("miri_test_libc_posix_realpath_alloc");
-    let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
-
-    // Cleanup before test.
-    remove_file(&path).ok();
-    // Create file.
-    drop(File::create(&path).unwrap());
-    unsafe {
-        let r = libc::realpath(c_path.as_ptr(), std::ptr::null_mut());
-        assert!(!r.is_null());
-        buf = CStr::from_ptr(r).to_bytes().to_vec();
-        libc::free(r as *mut _);
-    }
-    let canonical = PathBuf::from(OsString::from_vec(buf));
-    assert_eq!(path.file_name(), canonical.file_name());
-
-    // Cleanup after test.
-    remove_file(&path).unwrap();
-}
-
-/// Test non-allocating variant of `realpath`.
-fn test_posix_realpath_noalloc() {
-    use std::ffi::{CStr, CString};
-    use std::os::unix::ffi::OsStrExt;
-
-    let path = utils::tmp().join("miri_test_libc_posix_realpath_noalloc");
-    let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
-
-    let mut v = vec![0; libc::PATH_MAX as usize];
-
-    // Cleanup before test.
-    remove_file(&path).ok();
-    // Create file.
-    drop(File::create(&path).unwrap());
-    unsafe {
-        let r = libc::realpath(c_path.as_ptr(), v.as_mut_ptr());
-        assert!(!r.is_null());
-    }
-    let c = unsafe { CStr::from_ptr(v.as_ptr()) };
-    let canonical = PathBuf::from(c.to_str().expect("CStr to str"));
-
-    assert_eq!(path.file_name(), canonical.file_name());
-
-    // Cleanup after test.
-    remove_file(&path).unwrap();
-}
-
-/// Test failure cases for `realpath`.
-fn test_posix_realpath_errors() {
-    use std::ffi::CString;
-    use std::io::ErrorKind;
-
-    // Test nonexistent path returns an error.
-    let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed");
-    let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) };
-    assert!(r.is_null());
-    let e = std::io::Error::last_os_error();
-    assert_eq!(e.raw_os_error(), Some(libc::ENOENT));
-    assert_eq!(e.kind(), ErrorKind::NotFound);
-}
-
-#[cfg(target_os = "linux")]
-fn test_posix_fadvise() {
-    use std::io::Write;
-
-    let path = utils::tmp().join("miri_test_libc_posix_fadvise.txt");
-    // Cleanup before test
-    remove_file(&path).ok();
-
-    // Set up an open file
-    let mut file = File::create(&path).unwrap();
-    let bytes = b"Hello, World!\n";
-    file.write(bytes).unwrap();
-
-    // Test calling posix_fadvise on a file.
-    let result = unsafe {
-        libc::posix_fadvise(
-            file.as_raw_fd(),
-            0,
-            bytes.len().try_into().unwrap(),
-            libc::POSIX_FADV_DONTNEED,
-        )
-    };
-    drop(file);
-    remove_file(&path).unwrap();
-    assert_eq!(result, 0);
-}
-
-#[cfg(target_os = "linux")]
-fn test_sync_file_range() {
-    use std::io::Write;
-
-    let path = utils::tmp().join("miri_test_libc_sync_file_range.txt");
-    // Cleanup before test.
-    remove_file(&path).ok();
-
-    // Write to a file.
-    let mut file = File::create(&path).unwrap();
-    let bytes = b"Hello, World!\n";
-    file.write(bytes).unwrap();
-
-    // Test calling sync_file_range on the file.
-    let result_1 = unsafe {
-        libc::sync_file_range(
-            file.as_raw_fd(),
-            0,
-            0,
-            libc::SYNC_FILE_RANGE_WAIT_BEFORE
-                | libc::SYNC_FILE_RANGE_WRITE
-                | libc::SYNC_FILE_RANGE_WAIT_AFTER,
-        )
-    };
-    drop(file);
-
-    // Test calling sync_file_range on a file opened for reading.
-    let file = File::open(&path).unwrap();
-    let result_2 = unsafe {
-        libc::sync_file_range(
-            file.as_raw_fd(),
-            0,
-            0,
-            libc::SYNC_FILE_RANGE_WAIT_BEFORE
-                | libc::SYNC_FILE_RANGE_WRITE
-                | libc::SYNC_FILE_RANGE_WAIT_AFTER,
-        )
-    };
-    drop(file);
-
-    remove_file(&path).unwrap();
-    assert_eq!(result_1, 0);
-    assert_eq!(result_2, 0);
-}
+use std::mem::{self, transmute};
+use std::ptr;
 
 /// Tests whether each thread has its own `__errno_location`.
 fn test_thread_local_errno() {
+    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+    use libc::___errno as __errno_location;
     #[cfg(target_os = "linux")]
     use libc::__errno_location;
     #[cfg(any(target_os = "macos", target_os = "freebsd"))]
@@ -171,116 +29,6 @@ fn test_thread_local_errno() {
     }
 }
 
-/// Tests whether clock support exists at all
-fn test_clocks() {
-    let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
-    let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
-    assert_eq!(is_error, 0);
-    let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
-    assert_eq!(is_error, 0);
-    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
-    {
-        let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
-        assert_eq!(is_error, 0);
-        let is_error =
-            unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) };
-        assert_eq!(is_error, 0);
-    }
-    #[cfg(target_os = "macos")]
-    {
-        let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) };
-        assert_eq!(is_error, 0);
-    }
-}
-
-fn test_posix_gettimeofday() {
-    let mut tp = std::mem::MaybeUninit::<libc::timeval>::uninit();
-    let tz = std::ptr::null_mut::<libc::timezone>();
-    #[cfg(target_os = "macos")] // `tz` has a different type on macOS
-    let tz = tz as *mut libc::c_void;
-    let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz) };
-    assert_eq!(is_error, 0);
-    let tv = unsafe { tp.assume_init() };
-    assert!(tv.tv_sec > 0);
-    assert!(tv.tv_usec >= 0); // Theoretically this could be 0.
-
-    // Test that non-null tz returns an error.
-    let mut tz = std::mem::MaybeUninit::<libc::timezone>::uninit();
-    let tz_ptr = tz.as_mut_ptr();
-    #[cfg(target_os = "macos")] // `tz` has a different type on macOS
-    let tz_ptr = tz_ptr as *mut libc::c_void;
-    let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz_ptr) };
-    assert_eq!(is_error, -1);
-}
-
-fn test_localtime_r() {
-    use std::ffi::CStr;
-    use std::{env, ptr};
-
-    // Set timezone to GMT.
-    let key = "TZ";
-    env::set_var(key, "GMT");
-
-    const TIME_SINCE_EPOCH: libc::time_t = 1712475836;
-    let custom_time_ptr = &TIME_SINCE_EPOCH;
-    let mut tm = libc::tm {
-        tm_sec: 0,
-        tm_min: 0,
-        tm_hour: 0,
-        tm_mday: 0,
-        tm_mon: 0,
-        tm_year: 0,
-        tm_wday: 0,
-        tm_yday: 0,
-        tm_isdst: 0,
-        tm_gmtoff: 0,
-        tm_zone: std::ptr::null_mut::<libc::c_char>(),
-    };
-    let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) };
-
-    assert_eq!(tm.tm_sec, 56);
-    assert_eq!(tm.tm_min, 43);
-    assert_eq!(tm.tm_hour, 7);
-    assert_eq!(tm.tm_mday, 7);
-    assert_eq!(tm.tm_mon, 3);
-    assert_eq!(tm.tm_year, 124);
-    assert_eq!(tm.tm_wday, 0);
-    assert_eq!(tm.tm_yday, 97);
-    assert_eq!(tm.tm_isdst, -1);
-    assert_eq!(tm.tm_gmtoff, 0);
-    unsafe { assert_eq!(CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") };
-
-    // The returned value is the pointer passed in.
-    assert!(ptr::eq(res, &mut tm));
-
-    //Remove timezone setting.
-    env::remove_var(key);
-}
-
-fn test_isatty() {
-    // Testing whether our isatty shim returns the right value would require controlling whether
-    // these streams are actually TTYs, which is hard.
-    // For now, we just check that these calls are supported at all.
-    unsafe {
-        libc::isatty(libc::STDIN_FILENO);
-        libc::isatty(libc::STDOUT_FILENO);
-        libc::isatty(libc::STDERR_FILENO);
-
-        // But when we open a file, it is definitely not a TTY.
-        let path = utils::tmp().join("notatty.txt");
-        // Cleanup before test.
-        remove_file(&path).ok();
-        let file = File::create(&path).unwrap();
-
-        assert_eq!(libc::isatty(file.as_raw_fd()), 0);
-        assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOTTY);
-
-        // Cleanup after test.
-        drop(file);
-        remove_file(&path).unwrap();
-    }
-}
-
 fn test_memcpy() {
     unsafe {
         let src = [1i8, 2, 3];
@@ -306,7 +54,7 @@ fn test_memcpy() {
         libc::memcpy(
             &mut dest as *mut i32 as *mut libc::c_void,
             &src as *const i32 as *const libc::c_void,
-            std::mem::size_of::<i32>(),
+            mem::size_of::<i32>(),
         );
         assert_eq!(dest, src);
     }
@@ -317,7 +65,7 @@ fn test_memcpy() {
         libc::memcpy(
             &mut dest as *mut Option<i32> as *mut libc::c_void,
             &src as *const Option<i32> as *const libc::c_void,
-            std::mem::size_of::<Option<i32>>(),
+            mem::size_of::<Option<i32>>(),
         );
         assert_eq!(dest, src);
     }
@@ -328,7 +76,7 @@ fn test_memcpy() {
         libc::memcpy(
             &mut dest as *mut &'static i32 as *mut libc::c_void,
             &src as *const &'static i32 as *const libc::c_void,
-            std::mem::size_of::<&'static i32>(),
+            mem::size_of::<&'static i32>(),
         );
         assert_eq!(*dest, 123);
     }
@@ -388,7 +136,7 @@ fn test_dlsym() {
     assert_eq!(errno, libc::EBADF);
 }
 
-#[cfg(not(target_os = "macos"))]
+#[cfg(not(any(target_os = "macos", target_os = "illumos")))]
 fn test_reallocarray() {
     unsafe {
         let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2);
@@ -401,33 +149,94 @@ fn test_reallocarray() {
     }
 }
 
-fn main() {
-    test_posix_gettimeofday();
+fn test_memalign() {
+    // A normal allocation.
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::null_mut();
+        let align = 8;
+        let size = 64;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+        assert!(!ptr.is_null());
+        assert!(ptr.is_aligned_to(align));
+        ptr.cast::<u8>().write_bytes(1, size);
+        libc::free(ptr);
+    }
 
-    test_posix_realpath_alloc();
-    test_posix_realpath_noalloc();
-    test_posix_realpath_errors();
+    // Align > size.
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::null_mut();
+        let align = 64;
+        let size = 8;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+        assert!(!ptr.is_null());
+        assert!(ptr.is_aligned_to(align));
+        ptr.cast::<u8>().write_bytes(1, size);
+        libc::free(ptr);
+    }
 
-    test_thread_local_errno();
-    test_localtime_r();
+    // Size not multiple of align
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::null_mut();
+        let align = 16;
+        let size = 31;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+        assert!(!ptr.is_null());
+        assert!(ptr.is_aligned_to(align));
+        ptr.cast::<u8>().write_bytes(1, size);
+        libc::free(ptr);
+    }
 
-    test_isatty();
+    // Size == 0
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::null_mut();
+        let align = 64;
+        let size = 0;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+        // We are not required to return null if size == 0, but we currently do.
+        // It's fine to remove this assert if we start returning non-null pointers.
+        assert!(ptr.is_null());
+        assert!(ptr.is_aligned_to(align));
+        // Regardless of what we return, it must be `free`able.
+        libc::free(ptr);
+    }
 
-    test_clocks();
+    // Non-power of 2 align
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
+        let align = 15;
+        let size = 8;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
+        // The pointer is not modified on failure, posix_memalign(3) says:
+        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
+        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
+        assert_eq!(ptr.addr(), 0x1234567);
+    }
+
+    // Too small align (smaller than ptr)
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
+        let align = std::mem::size_of::<usize>() / 2;
+        let size = 8;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
+        // The pointer is not modified on failure, posix_memalign(3) says:
+        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
+        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
+        assert_eq!(ptr.addr(), 0x1234567);
+    }
+}
+
+fn main() {
+    test_thread_local_errno();
 
     test_dlsym();
 
     test_memcpy();
     test_strcpy();
 
-    #[cfg(not(target_os = "macos"))] // reallocarray does not exist on macOS
+    test_memalign();
+    #[cfg(not(any(target_os = "macos", target_os = "illumos")))]
     test_reallocarray();
 
-    // These are Linux-specific
     #[cfg(target_os = "linux")]
-    {
-        test_posix_fadvise();
-        test_sync_file_range();
-        test_sigrt();
-    }
+    test_sigrt();
 }
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs b/src/tools/miri/tests/pass-dep/shims/libc-random.rs
index 9c670cbd507..71e33522634 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-random.rs
@@ -1,9 +1,29 @@
 //@ignore-target-windows: no libc
-//@ignore-target-apple: no getrandom
-
-use std::ptr;
+//@revisions: isolation no_isolation
+//@[no_isolation]compile-flags: -Zmiri-disable-isolation
 
 fn main() {
+    test_getentropy();
+    #[cfg(not(target_os = "macos"))]
+    test_getrandom();
+}
+
+fn test_getentropy() {
+    use libc::getentropy;
+
+    let mut buf1 = [0u8; 256];
+    let mut buf2 = [0u8; 257];
+    unsafe {
+        assert_eq!(getentropy(buf1.as_mut_ptr() as *mut libc::c_void, buf1.len()), 0);
+        assert_eq!(getentropy(buf2.as_mut_ptr() as *mut libc::c_void, buf2.len()), -1);
+        assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::EIO);
+    }
+}
+
+#[cfg(not(target_os = "macos"))]
+fn test_getrandom() {
+    use std::ptr;
+
     let mut buf = [0u8; 5];
     unsafe {
         #[cfg(target_os = "linux")]
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-time.rs b/src/tools/miri/tests/pass-dep/shims/libc-time.rs
new file mode 100644
index 00000000000..69c75bd8caf
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/libc-time.rs
@@ -0,0 +1,93 @@
+//@ignore-target-windows: no libc on Windows
+//@compile-flags: -Zmiri-disable-isolation
+use std::ffi::CStr;
+use std::{env, mem, ptr};
+
+fn main() {
+    test_clocks();
+    test_posix_gettimeofday();
+    test_localtime_r();
+}
+
+/// Tests whether clock support exists at all
+fn test_clocks() {
+    let mut tp = mem::MaybeUninit::<libc::timespec>::uninit();
+    let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
+    assert_eq!(is_error, 0);
+    let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
+    assert_eq!(is_error, 0);
+    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
+    {
+        let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
+        assert_eq!(is_error, 0);
+        let is_error =
+            unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) };
+        assert_eq!(is_error, 0);
+    }
+    #[cfg(target_os = "macos")]
+    {
+        let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) };
+        assert_eq!(is_error, 0);
+    }
+}
+
+fn test_posix_gettimeofday() {
+    let mut tp = mem::MaybeUninit::<libc::timeval>::uninit();
+    let tz = ptr::null_mut::<libc::timezone>();
+    let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz.cast()) };
+    assert_eq!(is_error, 0);
+    let tv = unsafe { tp.assume_init() };
+    assert!(tv.tv_sec > 0);
+    assert!(tv.tv_usec >= 0); // Theoretically this could be 0.
+
+    // Test that non-null tz returns an error.
+    let mut tz = mem::MaybeUninit::<libc::timezone>::uninit();
+    let tz_ptr = tz.as_mut_ptr();
+    let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz_ptr.cast()) };
+    assert_eq!(is_error, -1);
+}
+
+fn test_localtime_r() {
+    // Set timezone to GMT.
+    let key = "TZ";
+    env::set_var(key, "GMT");
+
+    const TIME_SINCE_EPOCH: libc::time_t = 1712475836;
+    let custom_time_ptr = &TIME_SINCE_EPOCH;
+    let mut tm = libc::tm {
+        tm_sec: 0,
+        tm_min: 0,
+        tm_hour: 0,
+        tm_mday: 0,
+        tm_mon: 0,
+        tm_year: 0,
+        tm_wday: 0,
+        tm_yday: 0,
+        tm_isdst: 0,
+        tm_gmtoff: 0,
+        tm_zone: std::ptr::null_mut::<libc::c_char>(),
+    };
+    let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) };
+
+    assert_eq!(tm.tm_sec, 56);
+    assert_eq!(tm.tm_min, 43);
+    assert_eq!(tm.tm_hour, 7);
+    assert_eq!(tm.tm_mday, 7);
+    assert_eq!(tm.tm_mon, 3);
+    assert_eq!(tm.tm_year, 124);
+    assert_eq!(tm.tm_wday, 0);
+    assert_eq!(tm.tm_yday, 97);
+    assert_eq!(tm.tm_isdst, -1);
+    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+    assert_eq!(tm.tm_gmtoff, 0);
+    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+    unsafe {
+        assert_eq!(CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00")
+    };
+
+    // The returned value is the pointer passed in.
+    assert!(ptr::eq(res, &mut tm));
+
+    // Remove timezone setting.
+    env::remove_var(key);
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs
deleted file mode 100644
index db66b213416..00000000000
--- a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-//@ignore-target-windows: No libc on Windows
-
-#![feature(pointer_is_aligned_to)]
-#![feature(strict_provenance)]
-
-use core::ptr;
-
-fn main() {
-    // A normal allocation.
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 8;
-        let size = 64;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Align > size.
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 64;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Size not multiple of align
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 16;
-        let size = 31;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Size == 0
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 64;
-        let size = 0;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        // We are not required to return null if size == 0, but we currently do.
-        // It's fine to remove this assert if we start returning non-null pointers.
-        assert!(ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        // Regardless of what we return, it must be `free`able.
-        libc::free(ptr);
-    }
-
-    // Non-power of 2 align
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
-        let align = 15;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
-        // The pointer is not modified on failure, posix_memalign(3) says:
-        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
-        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
-        assert_eq!(ptr.addr(), 0x1234567);
-    }
-
-    // Too small align (smaller than ptr)
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
-        let align = std::mem::size_of::<usize>() / 2;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
-        // The pointer is not modified on failure, posix_memalign(3) says:
-        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
-        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
-        assert_eq!(ptr.addr(), 0x1234567);
-    }
-}
diff --git a/src/tools/miri/tests/pass/hello.rs b/src/tools/miri/tests/pass/hello.rs
index e7a11a969c0..2a02a7a9e20 100644
--- a/src/tools/miri/tests/pass/hello.rs
+++ b/src/tools/miri/tests/pass/hello.rs
@@ -1,3 +1,4 @@
 fn main() {
     println!("Hello, world!");
+    eprintln!("Hello, error!");
 }
diff --git a/src/tools/miri/tests/pass/hello.stderr b/src/tools/miri/tests/pass/hello.stderr
new file mode 100644
index 00000000000..445a1bc8fa4
--- /dev/null
+++ b/src/tools/miri/tests/pass/hello.stderr
@@ -0,0 +1 @@
+Hello, error!