about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/tools/miri/ci/ci.sh8
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs190
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs (renamed from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs)0
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs (renamed from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs)0
5 files changed, 70 insertions, 131 deletions
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 2e76838b001..6b57a294b65 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -150,10 +150,10 @@ case $HOST_TARGET in
     # Partially supported targets (tier 2)
     BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization)
     UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
-    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
-    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX threadname libc-time fs
-    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread available-parallelism libc-time tls
-    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX threadname pthread available-parallelism libc-time tls
+    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread libc-time fs
+    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX threadname pthread libc-time fs
+    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread sync available-parallelism libc-time tls
+    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX threadname pthread sync available-parallelism libc-time tls
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX
     TEST_TARGET=wasm32-wasip2          run_tests_minimal empty_main wasm heap_alloc libc-mem
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index 3535eacb447..114a457d71a 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -11,7 +11,7 @@ use crate::*;
 #[inline]
 fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
     Ok(match &*ecx.tcx.sess.target.os {
-        "linux" | "illumos" | "solaris" | "macos" => 0,
+        "linux" | "illumos" | "solaris" | "macos" | "freebsd" => 0,
         os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"),
     })
 }
@@ -43,21 +43,11 @@ fn mutexattr_set_kind<'tcx>(
     )
 }
 
-/// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from
-/// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values,
-/// but different behaviour, we need a way to distinguish them. We do this by
-/// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment
-/// in `pthread_mutexattr_settype` function.
-const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000;
-
-fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
-    Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"))
-}
-
-fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
-    let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL");
-    Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG))
-}
+/// To differentiate "the mutex kind has not been changed" from
+/// "the mutex kind has been set to PTHREAD_MUTEX_DEFAULT and that is
+/// equal to some other mutex kind", we make the default value of this
+/// field *not* PTHREAD_MUTEX_DEFAULT but this special flag.
+const PTHREAD_MUTEX_KIND_UNCHANGED: i32 = 0x8000000;
 
 /// The mutex kind.
 #[derive(Debug, Clone, Copy)]
@@ -78,13 +68,15 @@ pub struct AdditionalMutexData {
     pub address: u64,
 }
 
-// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
+// pthread_mutex_t is between 4 and 48 bytes, depending on the platform.
 // We ignore the platform layout and store our own fields:
 // - id: u32
 
 fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
+    // When adding a new OS, make sure we also support all its static initializers in
+    // `mutex_kind_from_static_initializer`!
     let offset = match &*ecx.tcx.sess.target.os {
-        "linux" | "illumos" | "solaris" => 0,
+        "linux" | "illumos" | "solaris" | "freebsd" => 0,
         // macOS stores a signature in the first bytes, so we have to move to offset 4.
         "macos" => 4,
         os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
@@ -113,7 +105,7 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
                 check_static_initializer("PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP");
                 check_static_initializer("PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP");
             }
-            "illumos" | "solaris" | "macos" => {
+            "illumos" | "solaris" | "macos" | "freebsd" => {
                 // No non-standard initializers.
             }
             os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
@@ -127,11 +119,10 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
 fn mutex_create<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
     mutex_ptr: &OpTy<'tcx>,
-    kind: i32,
+    kind: MutexKind,
 ) -> InterpResult<'tcx> {
     let mutex = ecx.deref_pointer(mutex_ptr)?;
     let address = mutex.ptr().addr().bytes();
-    let kind = translate_kind(ecx, kind)?;
     let data = Box::new(AdditionalMutexData { address, kind });
     ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?;
     Ok(())
@@ -151,7 +142,7 @@ fn mutex_get_id<'tcx>(
     let id = ecx.mutex_get_or_create_id(&mutex, mutex_id_offset(ecx)?, |ecx| {
         // This is called if a static initializer was used and the lock has not been assigned
         // an ID yet. We have to determine the mutex kind from the static initializer.
-        let kind = kind_from_static_initializer(ecx, &mutex)?;
+        let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
 
         Ok(Some(Box::new(AdditionalMutexData { kind, address })))
     })?;
@@ -168,40 +159,51 @@ fn mutex_get_id<'tcx>(
 }
 
 /// Returns the kind of a static initializer.
-fn kind_from_static_initializer<'tcx>(
+fn mutex_kind_from_static_initializer<'tcx>(
     ecx: &MiriInterpCx<'tcx>,
     mutex: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, MutexKind> {
-    // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
-    let kind = match &*ecx.tcx.sess.target.os {
+    Ok(match &*ecx.tcx.sess.target.os {
+        // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
         "linux" => {
             let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
             let kind_place =
                 mutex.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)?;
-            ecx.read_scalar(&kind_place)?.to_i32()?
+            let kind = ecx.read_scalar(&kind_place)?.to_i32()?;
+            // Here we give PTHREAD_MUTEX_DEFAULT priority so that
+            // PTHREAD_MUTEX_INITIALIZER behaves like `pthread_mutex_init` with a NULL argument.
+            if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") {
+                MutexKind::Default
+            } else {
+                mutex_translate_kind(ecx, kind)?
+            }
         }
-        "illumos" | "solaris" | "macos" => ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"),
-        os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
-    };
-
-    translate_kind(ecx, kind)
+        _ => MutexKind::Default,
+    })
 }
 
-fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, MutexKind> {
-    Ok(if is_mutex_kind_default(ecx, kind)? {
-        MutexKind::Default
-    } else if is_mutex_kind_normal(ecx, kind)? {
+fn mutex_translate_kind<'tcx>(
+    ecx: &MiriInterpCx<'tcx>,
+    kind: i32,
+) -> InterpResult<'tcx, MutexKind> {
+    Ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) {
         MutexKind::Normal
     } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
         MutexKind::ErrorCheck
     } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
         MutexKind::Recursive
+    } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
+        || kind == PTHREAD_MUTEX_KIND_UNCHANGED
+    {
+        // We check this *last* since PTHREAD_MUTEX_DEFAULT may be numerically equal to one of the
+        // others, and we want an explicit `mutexattr_settype` to work as expected.
+        MutexKind::Default
     } else {
         throw_unsup_format!("unsupported type of mutex: {kind}");
     })
 }
 
-// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
+// pthread_rwlock_t is between 4 and 56 bytes, depending on the platform.
 // We ignore the platform layout and store our own fields:
 // - id: u32
 
@@ -214,7 +216,7 @@ pub struct AdditionalRwLockData {
 
 fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
     let offset = match &*ecx.tcx.sess.target.os {
-        "linux" | "illumos" | "solaris" => 0,
+        "linux" | "illumos" | "solaris" | "freebsd" => 0,
         // macOS stores a signature in the first bytes, so we have to move to offset 4.
         "macos" => 4,
         os => throw_unsup_format!("`pthread_rwlock` is not supported on {os}"),
@@ -267,7 +269,7 @@ fn rwlock_get_id<'tcx>(
 #[inline]
 fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
     Ok(match &*ecx.tcx.sess.target.os {
-        "linux" | "illumos" | "solaris" => 0,
+        "linux" | "illumos" | "solaris" | "freebsd" => 0,
         // macOS does not have a clock attribute.
         os => throw_unsup_format!("`pthread_condattr` clock field is not supported on {os}"),
     })
@@ -286,11 +288,11 @@ fn condattr_get_clock_id<'tcx>(
     .to_i32()
 }
 
-fn translate_clock_id<'tcx>(ecx: &MiriInterpCx<'tcx>, raw_id: i32) -> InterpResult<'tcx, ClockId> {
-    // To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms,
-    // we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
-    // makes the clock 0 but CLOCK_REALTIME is 3.
-    Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") || raw_id == 0 {
+fn cond_translate_clock_id<'tcx>(
+    ecx: &MiriInterpCx<'tcx>,
+    raw_id: i32,
+) -> InterpResult<'tcx, ClockId> {
+    Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
         ClockId::Realtime
     } else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
         ClockId::Monotonic
@@ -313,14 +315,13 @@ fn condattr_set_clock_id<'tcx>(
     )
 }
 
-// pthread_cond_t.
+// pthread_cond_t can be only 4 bytes in size, depending on the platform.
 // We ignore the platform layout and store our own fields:
 // - id: u32
-// - clock: i32
 
 fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
     let offset = match &*ecx.tcx.sess.target.os {
-        "linux" | "illumos" | "solaris" => 0,
+        "linux" | "illumos" | "solaris" | "freebsd" => 0,
         // macOS stores a signature in the first bytes, so we have to move to offset 4.
         "macos" => 4,
         os => throw_unsup_format!("`pthread_cond` is not supported on {os}"),
@@ -344,30 +345,6 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
     Ok(offset)
 }
 
-fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
-    // macOS doesn't have a clock attribute, but to keep the code uniform we store
-    // a clock ID in the pthread_cond_t anyway. There's enough space.
-    let offset = 8;
-
-    // Sanity-check this against PTHREAD_COND_INITIALIZER (but only once):
-    // the clock must start out as CLOCK_REALTIME.
-    static SANITY: AtomicBool = AtomicBool::new(false);
-    if !SANITY.swap(true, Ordering::Relaxed) {
-        let static_initializer = ecx.eval_path(&["libc", "PTHREAD_COND_INITIALIZER"]);
-        let id_field = static_initializer
-            .offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)
-            .unwrap();
-        let id = ecx.read_scalar(&id_field).unwrap().to_i32().unwrap();
-        let id = translate_clock_id(ecx, id).expect("static initializer should be valid");
-        assert!(
-            matches!(id, ClockId::Realtime),
-            "PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME"
-        );
-    }
-
-    offset
-}
-
 #[derive(Debug, Clone, Copy)]
 enum ClockId {
     Realtime,
@@ -390,14 +367,9 @@ fn cond_get_id<'tcx>(
 ) -> InterpResult<'tcx, CondvarId> {
     let cond = ecx.deref_pointer(cond_ptr)?;
     let address = cond.ptr().addr().bytes();
-    let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |ecx| {
-        let raw_id = if ecx.tcx.sess.target.os == "macos" {
-            ecx.eval_libc_i32("CLOCK_REALTIME")
-        } else {
-            cond_get_clock_id(ecx, cond_ptr)?
-        };
-        let clock_id = translate_clock_id(ecx, raw_id)?;
-        Ok(Some(Box::new(AdditionalCondData { address, clock_id })))
+    let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| {
+        // This used the static initializer. The clock there is always CLOCK_REALTIME.
+        Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime })))
     })?;
 
     // Check that the mutex has not been moved since last use.
@@ -411,26 +383,12 @@ fn cond_get_id<'tcx>(
     Ok(id)
 }
 
-fn cond_get_clock_id<'tcx>(
-    ecx: &MiriInterpCx<'tcx>,
-    cond_ptr: &OpTy<'tcx>,
-) -> InterpResult<'tcx, i32> {
-    ecx.deref_pointer_and_read(
-        cond_ptr,
-        cond_clock_offset(ecx),
-        ecx.libc_ty_layout("pthread_cond_t"),
-        ecx.machine.layouts.i32,
-    )?
-    .to_i32()
-}
-
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
-        let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
-        mutexattr_set_kind(this, attr_op, default_kind)?;
+        mutexattr_set_kind(this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED)?;
 
         Ok(())
     }
@@ -443,30 +401,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let kind = this.read_scalar(kind_op)?.to_i32()?;
-        if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL") {
-            // In `glibc` implementation, the numeric values of
-            // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
-            // However, a mutex created by explicitly passing
-            // `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour
-            // from the default mutex for which the type was not explicitly
-            // specified. For a more detailed discussion, please see
-            // https://github.com/rust-lang/miri/issues/1419.
-            //
-            // To distinguish these two cases in already constructed mutexes, we
-            // use the same trick as glibc: for the case when
-            // `pthread_mutexattr_settype` is called explicitly, we set the
-            // `PTHREAD_MUTEX_NORMAL_FLAG` flag.
-            let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG;
-            // Check that after setting the flag, the kind is distinguishable
-            // from all other kinds.
-            assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"));
-            assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK"));
-            assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE"));
-            mutexattr_set_kind(this, attr_op, normal_kind)?;
-        } else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
+        if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL")
+            || kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
             || kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
             || kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
         {
+            // Make sure we do not mix this up with the "unchanged" kind.
+            assert_ne!(kind, PTHREAD_MUTEX_KIND_UNCHANGED);
             mutexattr_set_kind(this, attr_op, kind)?;
         } else {
             let einval = this.eval_libc_i32("EINVAL");
@@ -510,9 +451,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let attr = this.read_pointer(attr_op)?;
         let kind = if this.ptr_is_null(attr)? {
-            this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
+            MutexKind::Default
         } else {
-            mutexattr_get_kind(this, attr_op)?
+            mutex_translate_kind(this, mutexattr_get_kind(this, attr_op)?)?
         };
 
         mutex_create(this, mutex_op, kind)?;
@@ -624,15 +565,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
+        // Reading the field also has the side-effect that we detect double-`destroy`
+        // since we make the field unint below.
         let id = mutex_get_id(this, mutex_op)?;
 
         if this.mutex_is_locked(id) {
             throw_ub_format!("destroyed a locked mutex");
         }
 
-        // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
-        mutex_get_id(this, mutex_op)?;
-
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
         this.write_uninit(
             &this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
@@ -734,15 +674,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
 
+        // Reading the field also has the side-effect that we detect double-`destroy`
+        // since we make the field unint below.
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_locked(id) {
             throw_ub_format!("destroyed a locked rwlock");
         }
 
-        // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit.
-        rwlock_get_id(this, rwlock_op)?;
-
         // This might lead to false positives, see comment in pthread_mutexattr_destroy
         this.write_uninit(
             &this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
@@ -832,7 +771,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else {
             condattr_get_clock_id(this, attr_op)?
         };
-        let clock_id = translate_clock_id(this, clock_id)?;
+        let clock_id = cond_translate_clock_id(this, clock_id)?;
 
         let cond = this.deref_pointer(cond_op)?;
         let address = cond.ptr().addr().bytes();
@@ -930,11 +869,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
-        //NOTE: Destroying an uninit pthread_cond is UB. Make sure it's not uninit,
-        // by accessing at least once all of its fields that we use.
-
         let this = self.eval_context_mut();
 
+        // Reading the field also has the side-effect that we detect double-`destroy`
+        // since we make the field unint below.
         let id = cond_get_id(this, cond_op)?;
         if this.condvar_is_awaited(id) {
             throw_ub_format!("destroying an awaited conditional variable");
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
index 1038b8988f9..6723f2c6e77 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
@@ -4,7 +4,8 @@
 
 fn main() {
     unsafe {
-        let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
+        let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
+        assert_eq!(libc::pthread_mutexattr_init(&mut mutexattr as *mut _), 0);
         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs
index d758168c7c3..d758168c7c3 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait.rs
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs
index f1a3c5dc10d..f1a3c5dc10d 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc_pthread_cond_timedwait_isolated.rs