about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authortiif <pekyuan@gmail.com>2024-10-29 00:20:45 +0800
committertiif <pekyuan@gmail.com>2024-11-11 02:52:34 +0800
commitbfb36e35b98c9649005fc65fd92d690bdbbc7406 (patch)
tree0a438187a6d9262ed7e38e789613d99bf027c3b9 /src
parentf736269dd53baa0741b3272f118ea9919e880971 (diff)
downloadrust-bfb36e35b98c9649005fc65fd92d690bdbbc7406.tar.gz
rust-bfb36e35b98c9649005fc65fd92d690bdbbc7406.zip
Remove MutexID list
Diffstat (limited to 'src')
-rw-r--r--src/tools/miri/src/concurrency/sync.rs100
-rw-r--r--src/tools/miri/src/concurrency/thread.rs2
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs44
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs49
5 files changed, 111 insertions, 86 deletions
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 199aedfa6d2..43950495fb9 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -1,6 +1,9 @@
+use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::collections::hash_map::Entry;
+use std::default::Default;
 use std::ops::Not;
+use std::rc::Rc;
 use std::time::Duration;
 
 use rustc_data_structures::fx::FxHashMap;
@@ -44,8 +47,6 @@ macro_rules! declare_id {
 }
 pub(super) use declare_id;
 
-declare_id!(MutexId);
-
 /// The mutex state.
 #[derive(Default, Debug)]
 struct Mutex {
@@ -59,6 +60,21 @@ struct Mutex {
     clock: VClock,
 }
 
+#[derive(Default, Clone, Debug)]
+pub struct MutexRef(Rc<RefCell<Mutex>>);
+
+impl MutexRef {
+    fn new() -> Self {
+        MutexRef(Rc::new(RefCell::new(Mutex::default())))
+    }
+}
+
+impl VisitProvenance for MutexRef {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // Mutex contains no provenance.
+    }
+}
+
 declare_id!(RwLockId);
 
 /// The read-write lock state.
@@ -133,7 +149,6 @@ struct FutexWaiter {
 /// The state of all synchronization objects.
 #[derive(Default, Debug)]
 pub struct SynchronizationObjects {
-    mutexes: IndexVec<MutexId, Mutex>,
     rwlocks: IndexVec<RwLockId, RwLock>,
     condvars: IndexVec<CondvarId, Condvar>,
     pub(super) init_onces: IndexVec<InitOnceId, InitOnce>,
@@ -147,17 +162,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn condvar_reacquire_mutex(
         &mut self,
-        mutex: MutexId,
+        mutex_ref: &MutexRef,
         retval: Scalar,
         dest: MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        if this.mutex_is_locked(mutex) {
-            assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
-            this.mutex_enqueue_and_block(mutex, Some((retval, dest)));
+        if this.mutex_is_locked(mutex_ref) {
+            assert_ne!(this.mutex_get_owner(mutex_ref), this.active_thread());
+            this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest)));
         } else {
             // We can have it right now!
-            this.mutex_lock(mutex);
+            this.mutex_lock(mutex_ref);
             // Don't forget to write the return value.
             this.write_scalar(retval, &dest)?;
         }
@@ -166,10 +181,9 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 }
 
 impl SynchronizationObjects {
-    pub fn mutex_create(&mut self) -> MutexId {
-        self.mutexes.push(Default::default())
+    pub fn mutex_create(&mut self) -> MutexRef {
+        MutexRef::new()
     }
-
     pub fn rwlock_create(&mut self) -> RwLockId {
         self.rwlocks.push(Default::default())
     }
@@ -201,7 +215,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Helper for lazily initialized `alloc_extra.sync` data:
     /// this forces an immediate init.
-    fn lazy_sync_init<T: 'static + Copy>(
+    fn lazy_sync_init<T: 'static>(
         &mut self,
         primitive: &MPlaceTy<'tcx>,
         init_offset: Size,
@@ -227,7 +241,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// - If yes, fetches the data from `alloc_extra.sync`, or calls `missing_data` if that fails
     ///   and stores that in `alloc_extra.sync`.
     /// - Otherwise, calls `new_data` to initialize the primitive.
-    fn lazy_sync_get_data<T: 'static + Copy>(
+    ///
+    /// The return value is a *clone* of the stored data, so if you intend to mutate it
+    /// better wrap everything into an `Rc`.
+    fn lazy_sync_get_data<T: 'static + Clone>(
         &mut self,
         primitive: &MPlaceTy<'tcx>,
         init_offset: Size,
@@ -258,15 +275,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
             let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
             if let Some(data) = alloc_extra.get_sync::<T>(offset) {
-                interp_ok(*data)
+                interp_ok(data.clone())
             } else {
                 let data = missing_data()?;
-                alloc_extra.sync.insert(offset, Box::new(data));
+                alloc_extra.sync.insert(offset, Box::new(data.clone()));
                 interp_ok(data)
             }
         } else {
             let data = new_data(this)?;
-            this.lazy_sync_init(primitive, init_offset, data)?;
+            this.lazy_sync_init(primitive, init_offset, data.clone())?;
             interp_ok(data)
         }
     }
@@ -298,23 +315,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     #[inline]
     /// Get the id of the thread that currently owns this lock.
-    fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {
-        let this = self.eval_context_ref();
-        this.machine.sync.mutexes[id].owner.unwrap()
+    fn mutex_get_owner(&mut self, mutex_ref: &MutexRef) -> ThreadId {
+        mutex_ref.0.borrow().owner.unwrap()
     }
 
     #[inline]
     /// Check if locked.
-    fn mutex_is_locked(&self, id: MutexId) -> bool {
-        let this = self.eval_context_ref();
-        this.machine.sync.mutexes[id].owner.is_some()
+    fn mutex_is_locked(&self, mutex_ref: &MutexRef) -> bool {
+        mutex_ref.0.borrow().owner.is_some()
     }
 
     /// Lock by setting the mutex owner and increasing the lock count.
-    fn mutex_lock(&mut self, id: MutexId) {
+    fn mutex_lock(&mut self, mutex_ref: &MutexRef) {
         let this = self.eval_context_mut();
         let thread = this.active_thread();
-        let mutex = &mut this.machine.sync.mutexes[id];
+        let mut mutex = mutex_ref.0.borrow_mut();
         if let Some(current_owner) = mutex.owner {
             assert_eq!(thread, current_owner, "mutex already locked by another thread");
             assert!(
@@ -334,9 +349,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// count. If the lock count reaches 0, release the lock and potentially
     /// give to a new owner. If the lock was not locked by the current thread,
     /// return `None`.
-    fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<usize>> {
+    fn mutex_unlock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx, Option<usize>> {
         let this = self.eval_context_mut();
-        let mutex = &mut this.machine.sync.mutexes[id];
+        let mut mutex = mutex_ref.0.borrow_mut();
         interp_ok(if let Some(current_owner) = mutex.owner {
             // Mutex is locked.
             if current_owner != this.machine.threads.active_thread() {
@@ -354,8 +369,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         mutex.clock.clone_from(clock)
                     });
                 }
-                if let Some(thread) = this.machine.sync.mutexes[id].queue.pop_front() {
-                    this.unblock_thread(thread, BlockReason::Mutex(id))?;
+                let thread_id = mutex.queue.pop_front();
+                // We need to drop our mutex borrow before unblock_thread
+                // because it will be borrowed again in the unblock callback.
+                drop(mutex);
+                if thread_id.is_some() {
+                    this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?;
                 }
             }
             Some(old_lock_count)
@@ -372,24 +391,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     #[inline]
     fn mutex_enqueue_and_block(
         &mut self,
-        id: MutexId,
+        mutex_ref: &MutexRef,
         retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
     ) {
         let this = self.eval_context_mut();
-        assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
+        assert!(this.mutex_is_locked(mutex_ref), "queuing on unlocked mutex");
         let thread = this.active_thread();
-        this.machine.sync.mutexes[id].queue.push_back(thread);
+        mutex_ref.0.borrow_mut().queue.push_back(thread);
+        let mutex_ref = mutex_ref.clone();
         this.block_thread(
-            BlockReason::Mutex(id),
+            BlockReason::Mutex,
             None,
             callback!(
                 @capture<'tcx> {
-                    id: MutexId,
+                    mutex_ref: MutexRef,
                     retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
                 }
                 @unblock = |this| {
-                    assert!(!this.mutex_is_locked(id));
-                    this.mutex_lock(id);
+                    assert!(!this.mutex_is_locked(&mutex_ref));
+                    this.mutex_lock(&mutex_ref);
 
                     if let Some((retval, dest)) = retval_dest {
                         this.write_scalar(retval, &dest)?;
@@ -610,14 +630,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn condvar_wait(
         &mut self,
         condvar: CondvarId,
-        mutex: MutexId,
+        mutex_ref: MutexRef,
         timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
         retval_succ: Scalar,
         retval_timeout: Scalar,
         dest: MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        if let Some(old_locked_count) = this.mutex_unlock(mutex)? {
+        if let Some(old_locked_count) = this.mutex_unlock(&mutex_ref)? {
             if old_locked_count != 1 {
                 throw_unsup_format!(
                     "awaiting a condvar on a mutex acquired multiple times is not supported"
@@ -637,7 +657,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {
                     condvar: CondvarId,
-                    mutex: MutexId,
+                    mutex_ref: MutexRef,
                     retval_succ: Scalar,
                     retval_timeout: Scalar,
                     dest: MPlaceTy<'tcx>,
@@ -652,7 +672,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     // Try to acquire the mutex.
                     // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
-                    this.condvar_reacquire_mutex(mutex, retval_succ, dest)
+                    this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
                 }
                 @timeout = |this| {
                     // We have to remove the waiter from the queue again.
@@ -660,7 +680,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let waiters = &mut this.machine.sync.condvars[condvar].waiters;
                     waiters.retain(|waiter| *waiter != thread);
                     // Now get back the lock.
-                    this.condvar_reacquire_mutex(mutex, retval_timeout, dest)
+                    this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
                 }
             ),
         );
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 3946cb5ee54..596aaeca87a 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -162,7 +162,7 @@ pub enum BlockReason {
     /// Waiting for time to pass.
     Sleep,
     /// Blocked on a mutex.
-    Mutex(MutexId),
+    Mutex,
     /// Blocked on a condition variable.
     Condvar(CondvarId),
     /// Blocked on a reader-writer lock.
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 938d1ca319e..e8451dc5e50 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -121,7 +121,7 @@ pub use crate::concurrency::data_race::{
 };
 pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceId};
 pub use crate::concurrency::sync::{
-    CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects,
+    CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects,
 };
 pub use crate::concurrency::thread::{
     BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index 1df1202442a..431fd34e78f 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -14,10 +14,10 @@ use rustc_target::abi::Size;
 
 use crate::*;
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 enum MacOsUnfairLock {
     Poisoned,
-    Active { id: MutexId },
+    Active { mutex_ref: MutexRef },
 }
 
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -42,8 +42,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 interp_ok(MacOsUnfairLock::Poisoned)
             },
             |ecx| {
-                let id = ecx.machine.sync.mutex_create();
-                interp_ok(MacOsUnfairLock::Active { id })
+                let mutex_ref = ecx.machine.sync.mutex_create();
+                interp_ok(MacOsUnfairLock::Active { mutex_ref })
             },
         )
     }
@@ -54,7 +54,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // Trying to get a poisoned lock. Just block forever...
             this.block_thread(
                 BlockReason::Sleep,
@@ -69,17 +69,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(());
         };
 
-        if this.mutex_is_locked(id) {
-            if this.mutex_get_owner(id) == this.active_thread() {
+        if this.mutex_is_locked(&mutex_ref) {
+            if this.mutex_get_owner(&mutex_ref) == this.active_thread() {
                 // Matching the current macOS implementation: abort on reentrant locking.
                 throw_machine_stop!(TerminationInfo::Abort(
                     "attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned()
                 ));
             }
 
-            this.mutex_enqueue_and_block(id, None);
+            this.mutex_enqueue_and_block(&mutex_ref, None);
         } else {
-            this.mutex_lock(id);
+            this.mutex_lock(&mutex_ref);
         }
 
         interp_ok(())
@@ -92,18 +92,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // Trying to get a poisoned lock. That never works.
             this.write_scalar(Scalar::from_bool(false), dest)?;
             return interp_ok(());
         };
 
-        if this.mutex_is_locked(id) {
+        if this.mutex_is_locked(&mutex_ref) {
             // Contrary to the blocking lock function, this does not check for
             // reentrancy.
             this.write_scalar(Scalar::from_bool(false), dest)?;
         } else {
-            this.mutex_lock(id);
+            this.mutex_lock(&mutex_ref);
             this.write_scalar(Scalar::from_bool(true), dest)?;
         }
 
@@ -113,7 +113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             throw_machine_stop!(TerminationInfo::Abort(
                 "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
@@ -121,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         // Now, unlock.
-        if this.mutex_unlock(id)?.is_none() {
+        if this.mutex_unlock(&mutex_ref)?.is_none() {
             // Matching the current macOS implementation: abort.
             throw_machine_stop!(TerminationInfo::Abort(
                 "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
@@ -130,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If the lock is not locked by anyone now, it went quer.
         // Reset to zero so that it can be moved and initialized again for the next phase.
-        if !this.mutex_is_locked(id) {
+        if !this.mutex_is_locked(&mutex_ref) {
             let lock_place = this.deref_pointer_as(lock_op, this.machine.layouts.u32)?;
             this.write_scalar_atomic(Scalar::from_u32(0), &lock_place, AtomicWriteOrd::Relaxed)?;
         }
@@ -141,13 +141,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
             ));
         };
-        if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() {
+        if !this.mutex_is_locked(&mutex_ref)
+            || this.mutex_get_owner(&mutex_ref) != this.active_thread()
+        {
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
             ));
@@ -161,11 +163,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             return interp_ok(());
         };
-        if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() {
+        if this.mutex_is_locked(&mutex_ref)
+            && this.mutex_get_owner(&mutex_ref) == this.active_thread()
+        {
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned()
             ));
@@ -173,7 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If the lock is not locked by anyone now, it went quer.
         // Reset to zero so that it can be moved and initialized again for the next phase.
-        if !this.mutex_is_locked(id) {
+        if !this.mutex_is_locked(&mutex_ref) {
             let lock_place = this.deref_pointer_as(lock_op, this.machine.layouts.u32)?;
             this.write_scalar_atomic(Scalar::from_u32(0), &lock_place, AtomicWriteOrd::Relaxed)?;
         }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index a4beaa47baa..8760246e438 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -116,9 +116,9 @@ enum MutexKind {
     ErrorCheck,
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
 struct PthreadMutex {
-    id: MutexId,
+    mutex_ref: MutexRef,
     kind: MutexKind,
 }
 
@@ -175,15 +175,13 @@ fn mutex_create<'tcx>(
 ) -> InterpResult<'tcx, PthreadMutex> {
     let mutex = ecx.deref_pointer(mutex_ptr)?;
     let id = ecx.machine.sync.mutex_create();
-    let data = PthreadMutex { id, kind };
-    ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data)?;
+    let data = PthreadMutex { mutex_ref: id, kind };
+    ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data.clone())?;
     interp_ok(data)
 }
 
-/// Returns the `MutexId` of the mutex stored at `mutex_op`.
-///
-/// `mutex_get_id` will also check if the mutex has been moved since its first use and
-/// return an error if it has.
+/// Returns the mutex data stored at the address that `mutex_ptr` points to.
+/// Will raise an error if the mutex has been moved since its first use.
 fn mutex_get_data<'tcx, 'a>(
     ecx: &'a mut MiriInterpCx<'tcx>,
     mutex_ptr: &OpTy<'tcx>,
@@ -196,7 +194,7 @@ fn mutex_get_data<'tcx, 'a>(
         |ecx| {
             let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
             let id = ecx.machine.sync.mutex_create();
-            interp_ok(PthreadMutex { id, kind })
+            interp_ok(PthreadMutex { mutex_ref: id, kind })
         },
     )
 }
@@ -502,10 +500,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let mutex = mutex_get_data(this, mutex_op)?;
 
-        let ret = if this.mutex_is_locked(mutex.id) {
-            let owner_thread = this.mutex_get_owner(mutex.id);
+        let ret = if this.mutex_is_locked(&mutex.mutex_ref) {
+            let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
             if owner_thread != this.active_thread() {
-                this.mutex_enqueue_and_block(mutex.id, Some((Scalar::from_i32(0), dest.clone())));
+                this.mutex_enqueue_and_block(
+                    &mutex.mutex_ref,
+                    Some((Scalar::from_i32(0), dest.clone())),
+                );
                 return interp_ok(());
             } else {
                 // Trying to acquire the same mutex again.
@@ -517,14 +518,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
                     MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
                     MutexKind::Recursive => {
-                        this.mutex_lock(mutex.id);
+                        this.mutex_lock(&mutex.mutex_ref);
                         0
                     }
                 }
             }
         } else {
             // The mutex is unlocked. Let's lock it.
-            this.mutex_lock(mutex.id);
+            this.mutex_lock(&mutex.mutex_ref);
             0
         };
         this.write_scalar(Scalar::from_i32(ret), dest)?;
@@ -536,8 +537,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let mutex = mutex_get_data(this, mutex_op)?;
 
-        interp_ok(Scalar::from_i32(if this.mutex_is_locked(mutex.id) {
-            let owner_thread = this.mutex_get_owner(mutex.id);
+        interp_ok(Scalar::from_i32(if this.mutex_is_locked(&mutex.mutex_ref) {
+            let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
             if owner_thread != this.active_thread() {
                 this.eval_libc_i32("EBUSY")
             } else {
@@ -545,14 +546,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     MutexKind::Default | MutexKind::Normal | MutexKind::ErrorCheck =>
                         this.eval_libc_i32("EBUSY"),
                     MutexKind::Recursive => {
-                        this.mutex_lock(mutex.id);
+                        this.mutex_lock(&mutex.mutex_ref);
                         0
                     }
                 }
             }
         } else {
             // The mutex is unlocked. Let's lock it.
-            this.mutex_lock(mutex.id);
+            this.mutex_lock(&mutex.mutex_ref);
             0
         }))
     }
@@ -562,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let mutex = mutex_get_data(this, mutex_op)?;
 
-        if let Some(_old_locked_count) = this.mutex_unlock(mutex.id)? {
+        if let Some(_old_locked_count) = this.mutex_unlock(&mutex.mutex_ref)? {
             // The mutex was locked by the current thread.
             interp_ok(Scalar::from_i32(0))
         } else {
@@ -591,7 +592,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // since we make the field unint below.
         let mutex = mutex_get_data(this, mutex_op)?;
 
-        if this.mutex_is_locked(mutex.id) {
+        if this.mutex_is_locked(&mutex.mutex_ref) {
             throw_ub_format!("destroyed a locked mutex");
         }
 
@@ -823,11 +824,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let data = cond_get_data(this, cond_op)?;
-        let mutex_id = mutex_get_data(this, mutex_op)?.id;
+        let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref;
 
         this.condvar_wait(
             data.id,
-            mutex_id,
+            mutex_ref,
             None, // no timeout
             Scalar::from_i32(0),
             Scalar::from_i32(0), // retval_timeout -- unused
@@ -847,7 +848,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let data = cond_get_data(this, cond_op)?;
-        let mutex_id = mutex_get_data(this, mutex_op)?.id;
+        let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref;
 
         // Extract the timeout.
         let duration = match this
@@ -870,7 +871,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.condvar_wait(
             data.id,
-            mutex_id,
+            mutex_ref,
             Some((timeout_clock, TimeoutAnchor::Absolute, duration)),
             Scalar::from_i32(0),
             this.eval_libc("ETIMEDOUT"), // retval_timeout