about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-11-17 23:04:25 +0100
committerGitHub <noreply@github.com>2023-11-17 23:04:25 +0100
commit8acb27c165ce6b0af2705e653d3506ce607a9c0b (patch)
tree898853d56431513e4b6ec75649370c85e1dc4362
parentd1f18492a0de1e0fc3c248d79cf130b8e2381c29 (diff)
parentee48a3f24121d42ba32b69856d6d6e22ae01d8c7 (diff)
downloadrust-8acb27c165ce6b0af2705e653d3506ce607a9c0b.tar.gz
rust-8acb27c165ce6b0af2705e653d3506ce607a9c0b.zip
Rollup merge of #118022 - saethlin:miri, r=saethlin
Miri subtree update
-rwxr-xr-xsrc/tools/miri/ci.sh2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs58
-rw-r--r--src/tools/miri/src/machine.rs30
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs64
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs15
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs16
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml4
-rw-r--r--src/tools/miri/tests/compiletest.rs10
-rw-r--r--src/tools/miri/tests/pass-dep/getrandom.rs10
-rw-r--r--src/tools/miri/tests/pass-dep/getrandom_1.rs8
-rw-r--r--src/tools/miri/tests/pass-dep/rand.rs (renamed from src/tools/miri/tests/pass-dep/random.rs)11
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs20
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs5
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-misc.rs24
-rw-r--r--src/tools/miri/tests/pass-dep/shims/pthread-sync.rs (renamed from src/tools/miri/tests/pass-dep/shims/pthreads.rs)60
-rw-r--r--src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs51
17 files changed, 252 insertions, 138 deletions
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index f0917556c64..7808c9acf93 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -108,7 +108,7 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
-    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthreads atomic env/var
+    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc atomic env align
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
     MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
     MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 2beb3bfef9e..2a19781775b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-3aaa0f57b7b877ef58532a8de075d1e5a79142bf
+820f06b21f8373060ff7b515715b8440a6a6c197
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index a95571572d6..f9cc3acbd51 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -59,7 +59,7 @@ impl fmt::Debug for BorTag {
 #[derive(Debug)]
 pub struct FrameState {
     /// The ID of the call this frame corresponds to.
-    pub call_id: CallId,
+    call_id: CallId,
 
     /// If this frame is protecting any tags, they are listed here. We use this list to do
     /// incremental updates of the global list of protected tags stored in the
@@ -72,7 +72,7 @@ pub struct FrameState {
     ///
     /// This will contain one tag per reference passed to the function, so
     /// a size of 2 is enough for the vast majority of functions.
-    pub protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
+    protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
 }
 
 impl VisitTags for FrameState {
@@ -85,29 +85,29 @@ impl VisitTags for FrameState {
 #[derive(Debug)]
 pub struct GlobalStateInner {
     /// Borrow tracker method currently in use.
-    pub borrow_tracker_method: BorrowTrackerMethod,
+    borrow_tracker_method: BorrowTrackerMethod,
     /// Next unused pointer ID (tag).
-    pub next_ptr_tag: BorTag,
+    next_ptr_tag: BorTag,
     /// Table storing the "base" tag for each allocation.
     /// The base tag is the one used for the initial pointer.
     /// We need this in a separate table to handle cyclic statics.
-    pub base_ptr_tags: FxHashMap<AllocId, BorTag>,
+    base_ptr_tags: FxHashMap<AllocId, BorTag>,
     /// Next unused call ID (for protectors).
-    pub next_call_id: CallId,
+    next_call_id: CallId,
     /// All currently protected tags.
     /// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
     /// We add tags to this when they are created with a protector in `reborrow`, and
     /// we remove tags from this when the call which is protecting them returns, in
     /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
-    pub protected_tags: FxHashMap<BorTag, ProtectorKind>,
+    protected_tags: FxHashMap<BorTag, ProtectorKind>,
     /// The pointer ids to trace
-    pub tracked_pointer_tags: FxHashSet<BorTag>,
+    tracked_pointer_tags: FxHashSet<BorTag>,
     /// The call ids to trace
-    pub tracked_call_ids: FxHashSet<CallId>,
+    tracked_call_ids: FxHashSet<CallId>,
     /// Whether to recurse into datatypes when searching for pointers to retag.
-    pub retag_fields: RetagFields,
+    retag_fields: RetagFields,
     /// Whether `core::ptr::Unique` gets special (`Box`-like) handling.
-    pub unique_is_unique: bool,
+    unique_is_unique: bool,
 }
 
 impl VisitTags for GlobalStateInner {
@@ -194,7 +194,7 @@ impl GlobalStateInner {
     }
 
     /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation!
-    pub fn new_ptr(&mut self) -> BorTag {
+    fn new_ptr(&mut self) -> BorTag {
         let id = self.next_ptr_tag;
         self.next_ptr_tag = id.succ().unwrap();
         id
@@ -210,7 +210,7 @@ impl GlobalStateInner {
         FrameState { call_id, protected_tags: SmallVec::new() }
     }
 
-    pub fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
+    fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
         for (_, tag) in &frame
             .borrow_tracker
             .as_ref()
@@ -355,6 +355,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed),
         }
     }
+
+    fn on_stack_pop(
+        &self,
+        frame: &Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_ref();
+        let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap();
+        // The body of this loop needs `borrow_tracker` immutably
+        // so we can't move this code inside the following `end_call`.
+        for (alloc_id, tag) in &frame
+            .extra
+            .borrow_tracker
+            .as_ref()
+            .expect("we should have borrow tracking data")
+            .protected_tags
+        {
+            // Just because the tag is protected doesn't guarantee that
+            // the allocation still exists (weak protectors allow deallocations)
+            // so we must check that the allocation exists.
+            // If it does exist, then we have the guarantee that the
+            // pointer is readable, and the implicit read access inserted
+            // will never cause UB on the pointer itself.
+            let (_, _, kind) = this.get_alloc_info(*alloc_id);
+            if matches!(kind, AllocKind::LiveData) {
+                let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap();
+                let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
+                alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;
+            }
+        }
+        borrow_tracker.borrow_mut().end_call(&frame.extra);
+        Ok(())
+    }
 }
 
 /// Extra per-allocation data for borrow tracking
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index d5775912eab..2085df7d06f 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1409,34 +1409,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     ) -> InterpResult<'tcx> {
         // We want this *before* the return value copy, because the return place itself is protected
         // until we do `end_call` here.
-        if let Some(global_borrow_tracker) = &ecx.machine.borrow_tracker {
-            // The body of this loop needs `global_borrow_tracker` immutably
-            // so we can't move this code inside the following `end_call`.
-            for (alloc_id, tag) in &frame
-                .extra
-                .borrow_tracker
-                .as_ref()
-                .expect("we should have borrow tracking data")
-                .protected_tags
-            {
-                // Just because the tag is protected doesn't guarantee that
-                // the allocation still exists (weak protectors allow deallocations)
-                // so we must check that the allocation exists.
-                // If it does exist, then we have the guarantee that the
-                // pointer is readable, and the implicit read access inserted
-                // will never cause UB on the pointer itself.
-                let (_, _, kind) = ecx.get_alloc_info(*alloc_id);
-                if matches!(kind, AllocKind::LiveData) {
-                    let alloc_extra = ecx.get_alloc_extra(*alloc_id).unwrap();
-                    let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
-                    alloc_borrow_tracker.release_protector(
-                        &ecx.machine,
-                        global_borrow_tracker,
-                        *tag,
-                    )?;
-                }
-            }
-            global_borrow_tracker.borrow_mut().end_call(&frame.extra);
+        if ecx.machine.borrow_tracker.is_some() {
+            ecx.on_stack_pop(frame)?;
         }
         Ok(())
     }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index c013d275029..d155623eb7b 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -27,6 +27,8 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
         // `signal` is set up as a weak symbol in `init_extern_statics` (on Android) so we might as
         // well allow it in `dlsym`.
         "signal" => true,
+        // needed at least on macOS to avoid file-based fallback in getrandom
+        "getentropy" => true,
         // Give specific OSes a chance to allow their symbols.
         _ =>
             match target_os {
@@ -250,6 +252,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_scalar(result, dest)?;
             }
 
+            "reallocarray" => {
+                // Currently this function does not exist on all Unixes, e.g. on macOS.
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd") {
+                    throw_unsup_format!(
+                        "`reallocarray` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+                let [ptr, nmemb, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let ptr = this.read_pointer(ptr)?;
+                let nmemb = this.read_target_usize(nmemb)?;
+                let size = this.read_target_usize(size)?;
+                // reallocarray checks a possible overflow and returns ENOMEM
+                // if that happens.
+                //
+                // Linux: https://www.unix.com/man-page/linux/3/reallocarray/
+                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
+                match nmemb.checked_mul(size) {
+                    None => {
+                        let einval = this.eval_libc("ENOMEM");
+                        this.set_last_error(einval)?;
+                        this.write_null(dest)?;
+                    }
+                    Some(len) => {
+                        let res = this.realloc(ptr, len, MiriMemoryKind::C)?;
+                        this.write_pointer(res, dest)?;
+                    }
+                }
+            }
+
             // Dynamic symbol loading
             "dlsym" => {
                 let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -525,6 +558,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let result = this.getpid()?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "getentropy" => {
+                // This function is non-standard but exists with the same signature and behavior on
+                // Linux, macOS, and FreeBSD.
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd") {
+                    throw_unsup_format!(
+                        "`getentropy` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+
+                let [buf, bufsize] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let buf = this.read_pointer(buf)?;
+                let bufsize = this.read_target_usize(bufsize)?;
+
+                // getentropy sets errno to EIO when the buffer size exceeds 256 bytes.
+                // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=getentropy&sektion=3&format=html
+                // Linux: https://man7.org/linux/man-pages/man3/getentropy.3.html
+                // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
+                if bufsize > 256 {
+                    let err = this.eval_libc("EIO");
+                    this.set_last_error(err)?;
+                    this.write_scalar(Scalar::from_i32(-1), dest)?
+                } else {
+                    this.gen_random(buf, bufsize)?;
+                    this.write_scalar(Scalar::from_i32(0), 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.
@@ -594,7 +655,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_int(super::UID, dest)?;
             }
 
-            "getpwuid_r" if this.frame_in_std() => {
+            "getpwuid_r"
+            if this.frame_in_std() => {
                 let [uid, pwd, buf, buflen, result] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
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 96e322c4cf5..7c843e106ea 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -47,6 +47,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.read_scalar(len)?,
                 )?;
             }
+            "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)?;
+            }
 
             // errno
             "__error" => {
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 5881a3f46f2..e8f35e7ba57 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -6,8 +6,8 @@ use shims::foreign_items::EmulateForeignItemResult;
 use shims::unix::fs::EvalContextExt as _;
 use shims::unix::thread::EvalContextExt as _;
 
-pub fn is_dyn_sym(name: &str) -> bool {
-    matches!(name, "getentropy")
+pub fn is_dyn_sym(_name: &str) -> bool {
+    false
 }
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@@ -113,18 +113,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_scalar(result, dest)?;
             }
 
-            // Random generation related shims
-            "getentropy" => {
-                let [buf, bufsize] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let buf = this.read_pointer(buf)?;
-                let bufsize = this.read_target_usize(bufsize)?;
-
-                this.gen_random(buf, bufsize)?;
-
-                this.write_scalar(Scalar::from_i32(0), dest)?; // KERN_SUCCESS
-            }
-
             // Access to command-line arguments
             "_NSGetArgc" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 670f5c895cb..d54560608dc 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -12,8 +12,8 @@ edition = "2021"
 libc = "0.2"
 num_cpus = "1.10.1"
 
-getrandom_1 = { package = "getrandom", version = "0.1" }
-getrandom = { version = "0.2", features = ["js"] }
+getrandom_01 = { package = "getrandom", version = "0.1" }
+getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
 rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index dbf559631ea..91df4985c0f 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -79,6 +79,11 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
         program.args.push(flag);
     }
 
+    // Add a test env var to do environment communication tests.
+    program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
+    // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
+    program.envs.push(("MIRI_TEMP".into(), Some(env::temp_dir().into())));
+
     let mut config = Config {
         target: Some(target.to_owned()),
         stderr_filters: STDERR.clone(),
@@ -232,11 +237,6 @@ fn main() -> Result<()> {
         }
     }
 
-    // Add a test env var to do environment communication tests.
-    env::set_var("MIRI_ENV_VAR_TEST", "0");
-    // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
-    env::set_var("MIRI_TEMP", env::temp_dir());
-
     ui(Mode::Pass, "tests/pass", &target, WithoutDependencies)?;
     ui(Mode::Pass, "tests/pass-dep", &target, WithDependencies)?;
     ui(Mode::Panic, "tests/panic", &target, WithDependencies)?;
diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs
new file mode 100644
index 00000000000..c0d9296a9a6
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/getrandom.rs
@@ -0,0 +1,10 @@
+// mac-os `getrandom_01` does some pointer shenanigans
+//@compile-flags: -Zmiri-permissive-provenance
+
+/// Test direct calls of getrandom 0.1 and 0.2.
+/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path).
+fn main() {
+    let mut data = vec![0; 16];
+    getrandom_01::getrandom(&mut data).unwrap();
+    getrandom_02::getrandom(&mut data).unwrap();
+}
diff --git a/src/tools/miri/tests/pass-dep/getrandom_1.rs b/src/tools/miri/tests/pass-dep/getrandom_1.rs
deleted file mode 100644
index 2c7bd93fbdb..00000000000
--- a/src/tools/miri/tests/pass-dep/getrandom_1.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// mac-os `getrandom_1` does some pointer shenanigans
-//@compile-flags: -Zmiri-permissive-provenance
-
-/// Test old version of `getrandom`.
-fn main() {
-    let mut data = vec![0; 16];
-    getrandom_1::getrandom(&mut data).unwrap();
-}
diff --git a/src/tools/miri/tests/pass-dep/random.rs b/src/tools/miri/tests/pass-dep/rand.rs
index 0cd8b06d63d..0dce6d86cf4 100644
--- a/src/tools/miri/tests/pass-dep/random.rs
+++ b/src/tools/miri/tests/pass-dep/rand.rs
@@ -1,10 +1,13 @@
 //@compile-flags: -Zmiri-strict-provenance
-use rand::{rngs::SmallRng, Rng, SeedableRng};
+use rand::prelude::*;
 
+// Test using the `rand` crate to generate randomness.
 fn main() {
-    // Test `getrandom` directly.
-    let mut data = vec![0; 16];
-    getrandom::getrandom(&mut data).unwrap();
+    // Fully deterministic seeding.
+    let mut rng = SmallRng::seed_from_u64(42);
+    let _val = rng.gen::<i32>();
+    let _val = rng.gen::<isize>();
+    let _val = rng.gen::<i128>();
 
     // Try seeding with "real" entropy.
     let mut rng = SmallRng::from_entropy();
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs b/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs
new file mode 100644
index 00000000000..4b863f68516
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/libc-getentropy.rs
@@ -0,0 +1,20 @@
+//@ignore-target-windows: no libc
+
+// on macOS this is not in the `libc` crate.
+#[cfg(target_os = "macos")]
+extern "C" {
+    fn getentropy(bytes: *mut libc::c_void, count: libc::size_t) -> libc::c_int;
+}
+
+#[cfg(not(target_os = "macos"))]
+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.rs b/src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs
index a1436c7319d..9c670cbd507 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-getrandom.rs
@@ -1,10 +1,12 @@
-//@only-target-linux
+//@ignore-target-windows: no libc
+//@ignore-target-apple: no getrandom
 
 use std::ptr;
 
 fn main() {
     let mut buf = [0u8; 5];
     unsafe {
+        #[cfg(target_os = "linux")]
         assert_eq!(
             libc::syscall(
                 libc::SYS_getrandom,
@@ -14,6 +16,7 @@ fn main() {
             ),
             0,
         );
+        #[cfg(target_os = "linux")]
         assert_eq!(
             libc::syscall(
                 libc::SYS_getrandom,
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 40d3fa19e53..de1acb13cbe 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -172,6 +172,7 @@ fn test_thread_local_errno() {
 }
 
 /// Tests whether clock support exists at all
+#[cfg(not(target_os = "freebsd"))]
 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()) };
@@ -237,6 +238,7 @@ fn test_isatty() {
     }
 }
 
+#[cfg(not(target_os = "freebsd"))]
 fn test_posix_mkstemp() {
     use std::ffi::CString;
     use std::ffi::OsStr;
@@ -388,8 +390,23 @@ fn test_dlsym() {
     assert_eq!(errno, libc::EBADF);
 }
 
+#[cfg(not(target_os = "macos"))]
+fn test_reallocarray() {
+    unsafe {
+        let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2);
+        assert!(!p.is_null());
+        libc::free(p);
+        p = libc::malloc(16);
+        let r = libc::reallocarray(p, 2, 32);
+        assert!(!r.is_null());
+        libc::free(r);
+    }
+}
+
 fn main() {
     test_posix_gettimeofday();
+
+    #[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
     test_posix_mkstemp();
 
     test_posix_realpath_alloc();
@@ -399,12 +416,19 @@ fn main() {
     test_thread_local_errno();
 
     test_isatty();
+
+    #[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
     test_clocks();
+
     test_dlsym();
 
     test_memcpy();
     test_strcpy();
 
+    #[cfg(not(target_os = "macos"))] // reallocarray does not exist on macOS
+    test_reallocarray();
+
+    // These are Linux-specific
     #[cfg(target_os = "linux")]
     {
         test_posix_fadvise();
diff --git a/src/tools/miri/tests/pass-dep/shims/pthreads.rs b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
index 3bb6f83ec2a..4cc5b7d68a3 100644
--- a/src/tools/miri/tests/pass-dep/shims/pthreads.rs
+++ b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
@@ -1,26 +1,15 @@
 //@ignore-target-windows: No libc on Windows
-use std::ffi::CStr;
-#[cfg(not(target_os = "freebsd"))]
-use std::ffi::CString;
-use std::thread;
 
 fn main() {
-    test_named_thread_truncation();
-
-    #[cfg(not(target_os = "freebsd"))]
     test_mutex_libc_init_recursive();
-    #[cfg(not(target_os = "freebsd"))]
     test_mutex_libc_init_normal();
-    #[cfg(not(target_os = "freebsd"))]
     test_mutex_libc_init_errorcheck();
-    #[cfg(not(target_os = "freebsd"))]
     test_rwlock_libc_static_initializer();
 
     #[cfg(target_os = "linux")]
     test_mutex_libc_static_initializer_recursive();
 }
 
-#[cfg(not(target_os = "freebsd"))]
 fn test_mutex_libc_init_recursive() {
     unsafe {
         let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
@@ -45,7 +34,6 @@ fn test_mutex_libc_init_recursive() {
     }
 }
 
-#[cfg(not(target_os = "freebsd"))]
 fn test_mutex_libc_init_normal() {
     unsafe {
         let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
@@ -68,7 +56,6 @@ fn test_mutex_libc_init_normal() {
     }
 }
 
-#[cfg(not(target_os = "freebsd"))]
 fn test_mutex_libc_init_errorcheck() {
     unsafe {
         let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
@@ -114,7 +101,6 @@ fn test_mutex_libc_static_initializer_recursive() {
 // Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we
 // need to go a layer deeper and test the behavior of the libc functions, because
 // std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers.
-#[cfg(not(target_os = "freebsd"))]
 fn test_rwlock_libc_static_initializer() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
     unsafe {
@@ -139,49 +125,3 @@ fn test_rwlock_libc_static_initializer() {
         assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0);
     }
 }
-
-fn test_named_thread_truncation() {
-    let long_name = std::iter::once("test_named_thread_truncation")
-        .chain(std::iter::repeat(" yada").take(100))
-        .collect::<String>();
-
-    fn set_thread_name(name: &CStr) -> i32 {
-        #[cfg(target_os = "linux")]
-        return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) };
-        #[cfg(target_os = "freebsd")]
-        unsafe {
-            // pthread_set_name_np does not return anything
-            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast());
-            return 0;
-        };
-        #[cfg(target_os = "macos")]
-        return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) };
-    }
-
-    let result = thread::Builder::new().name(long_name.clone()).spawn(move || {
-        // Rust remembers the full thread name itself.
-        assert_eq!(thread::current().name(), Some(long_name.as_str()));
-
-        // But the system is limited -- make sure we successfully set a truncation.
-        let mut buf = vec![0u8; long_name.len() + 1];
-        #[cfg(not(target_os = "freebsd"))]
-        unsafe {
-            libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
-        };
-        #[cfg(target_os = "freebsd")]
-        unsafe {
-            libc::pthread_get_name_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
-        };
-        let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
-        assert!(cstr.to_bytes().len() >= 15, "name is too short: len={}", cstr.to_bytes().len()); // POSIX seems to promise at least 15 chars
-        assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
-
-        // Also test directly calling pthread_setname to check its return value.
-        assert_eq!(set_thread_name(&cstr), 0);
-        // But with a too long name it should fail (except on FreeBSD where the
-        // function has no return, hence cannot indicate failure).
-        #[cfg(not(target_os = "freebsd"))]
-        assert_ne!(set_thread_name(&CString::new(long_name).unwrap()), 0);
-    });
-    result.unwrap().join().unwrap();
-}
diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs
new file mode 100644
index 00000000000..bc782044d4d
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs
@@ -0,0 +1,51 @@
+//@ignore-target-windows: No libc on Windows
+use std::ffi::CStr;
+#[cfg(not(target_os = "freebsd"))]
+use std::ffi::CString;
+use std::thread;
+
+fn main() {
+    let long_name = std::iter::once("test_named_thread_truncation")
+        .chain(std::iter::repeat(" yada").take(100))
+        .collect::<String>();
+
+    fn set_thread_name(name: &CStr) -> i32 {
+        #[cfg(target_os = "linux")]
+        return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) };
+        #[cfg(target_os = "freebsd")]
+        unsafe {
+            // pthread_set_name_np does not return anything
+            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast());
+            return 0;
+        };
+        #[cfg(target_os = "macos")]
+        return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) };
+    }
+
+    let result = thread::Builder::new().name(long_name.clone()).spawn(move || {
+        // Rust remembers the full thread name itself.
+        assert_eq!(thread::current().name(), Some(long_name.as_str()));
+
+        // But the system is limited -- make sure we successfully set a truncation.
+        let mut buf = vec![0u8; long_name.len() + 1];
+        #[cfg(not(target_os = "freebsd"))]
+        unsafe {
+            libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
+        };
+        #[cfg(target_os = "freebsd")]
+        unsafe {
+            libc::pthread_get_name_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
+        };
+        let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+        assert!(cstr.to_bytes().len() >= 15, "name is too short: len={}", cstr.to_bytes().len()); // POSIX seems to promise at least 15 chars
+        assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
+
+        // Also test directly calling pthread_setname to check its return value.
+        assert_eq!(set_thread_name(&cstr), 0);
+        // But with a too long name it should fail (except on FreeBSD where the
+        // function has no return, hence cannot indicate failure).
+        #[cfg(not(target_os = "freebsd"))]
+        assert_ne!(set_thread_name(&CString::new(long_name).unwrap()), 0);
+    });
+    result.unwrap().join().unwrap();
+}