Skip to content

Commit 9cb5305

Browse files
committed
macOS os_unfair_lock: also store ID outside addressable memory
1 parent e48beb0 commit 9cb5305

File tree

4 files changed

+42
-49
lines changed

4 files changed

+42
-49
lines changed

src/concurrency/sync.rs

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -236,48 +236,26 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
236236
}
237237
}
238238

239-
// Public interface to synchronization primitives. Please note that in most
240-
// cases, the function calls are infallible and it is the client's (shim
241-
// implementation's) responsibility to detect and deal with erroneous
242-
// situations.
243-
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
244-
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
245-
/// Eagerly create and initialize a new mutex.
246-
fn mutex_create(&mut self) -> MutexId {
247-
let this = self.eval_context_mut();
248-
this.machine.sync.mutexes.push(Default::default())
249-
}
250-
251-
/// Lazily create a new mutex.
252-
/// `initialize_data` must return any additional data that a user wants to associate with the mutex.
253-
fn mutex_get_or_create_id(
254-
&mut self,
255-
lock: &MPlaceTy<'tcx>,
256-
offset: u64,
257-
) -> InterpResult<'tcx, MutexId> {
258-
let this = self.eval_context_mut();
259-
this.get_or_create_id(
260-
lock,
261-
offset,
262-
|ecx| &mut ecx.machine.sync.mutexes,
263-
|_ecx| interp_ok(Mutex::default()),
264-
)?
265-
.ok_or_else(|| err_ub_format!("mutex has invalid ID"))
266-
.into()
239+
impl SynchronizationObjects {
240+
pub fn mutex_create(&mut self) -> MutexId {
241+
self.mutexes.push(Default::default())
267242
}
268243

269-
/// Eagerly create and initialize a new rwlock.
270-
fn rwlock_create(&mut self) -> RwLockId {
271-
let this = self.eval_context_mut();
272-
this.machine.sync.rwlocks.push(Default::default())
244+
pub fn rwlock_create(&mut self) -> RwLockId {
245+
self.rwlocks.push(Default::default())
273246
}
274247

275-
/// Eagerly create and initialize a new condvar.
276-
fn condvar_create(&mut self) -> CondvarId {
277-
let this = self.eval_context_mut();
278-
this.machine.sync.condvars.push(Default::default())
248+
pub fn condvar_create(&mut self) -> CondvarId {
249+
self.condvars.push(Default::default())
279250
}
251+
}
280252

253+
// Public interface to synchronization primitives. Please note that in most
254+
// cases, the function calls are infallible and it is the client's (shim
255+
// implementation's) responsibility to detect and deal with erroneous
256+
// situations.
257+
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
258+
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
281259
#[inline]
282260
/// Get the id of the thread that currently owns this lock.
283261
fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {

src/machine.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ impl VisitProvenance for AllocExtra<'_> {
362362
}
363363
}
364364

365+
impl<'tcx> AllocExtra<'tcx> {
366+
pub fn get_sync<T: 'static>(&self, offset: Size) -> Option<&T> {
367+
self.sync.get(&offset).and_then(|s| s.downcast_ref::<T>())
368+
}
369+
}
370+
365371
/// Precomputed layouts of primitive types
366372
pub struct PrimitiveLayouts<'tcx> {
367373
pub unit: TyAndLayout<'tcx>,

src/shims/unix/macos/sync.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,26 @@
1212
1313
use crate::*;
1414

15+
struct LockData {
16+
id: MutexId,
17+
}
18+
1519
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
1620
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
1721
fn os_unfair_lock_getid(&mut self, lock_ptr: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> {
1822
let this = self.eval_context_mut();
1923
let lock = this.deref_pointer(lock_ptr)?;
20-
// os_unfair_lock holds a 32-bit value, is initialized with zero and
21-
// must be assumed to be opaque. Therefore, we can just store our
22-
// internal mutex ID in the structure without anyone noticing.
23-
this.mutex_get_or_create_id(&lock, /* offset */ 0)
24+
// We store the mutex ID in the `sync` metadata. This means that when the lock is moved,
25+
// that's just implicitly creating a new lock at the new location.
26+
let (alloc, offset, _) = this.ptr_get_alloc_id(lock.ptr(), 0)?;
27+
let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc)?;
28+
if let Some(data) = alloc_extra.get_sync::<LockData>(offset) {
29+
interp_ok(data.id)
30+
} else {
31+
let id = machine.sync.mutex_create();
32+
alloc_extra.sync.insert(offset, Box::new(LockData { id }));
33+
interp_ok(id)
34+
}
2435
}
2536
}
2637

src/shims/unix/sync.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,9 @@ fn sync_get_data<'tcx, T: 'static + Copy>(
8080
// If it is initialized, it must be found in the "sync primitive" table,
8181
// or else it has been moved illegally.
8282
let (alloc, offset, _) = ecx.ptr_get_alloc_id(primitive.ptr(), 0)?;
83-
let (alloc_extra, _machine) = ecx.get_alloc_extra_mut(alloc)?;
83+
let alloc_extra = ecx.get_alloc_extra(alloc)?;
8484
let data = alloc_extra
85-
.sync
86-
.get(&offset)
87-
.and_then(|s| s.downcast_ref::<T>())
85+
.get_sync::<T>(offset)
8886
.ok_or_else(|| err_ub_format!("`{name}` can't be moved after first use"))?;
8987
interp_ok(Some(*data))
9088
} else {
@@ -174,7 +172,7 @@ enum MutexKind {
174172

175173
#[derive(Debug, Clone, Copy)]
176174
/// Additional data that we attach with each mutex instance.
177-
pub struct MutexData {
175+
struct MutexData {
178176
id: MutexId,
179177
kind: MutexKind,
180178
}
@@ -228,7 +226,7 @@ fn mutex_create<'tcx>(
228226
kind: MutexKind,
229227
) -> InterpResult<'tcx, MutexData> {
230228
let mutex = ecx.deref_pointer(mutex_ptr)?;
231-
let id = ecx.mutex_create();
229+
let id = ecx.machine.sync.mutex_create();
232230
let data = MutexData { id, kind };
233231
sync_init(ecx, &mutex, mutex_init_offset(ecx)?, data)?;
234232
interp_ok(data)
@@ -290,7 +288,7 @@ fn mutex_kind_from_static_initializer<'tcx>(
290288

291289
#[derive(Debug, Copy, Clone)]
292290
/// Additional data that we attach with each rwlock instance.
293-
pub struct RwLockData {
291+
struct RwLockData {
294292
id: RwLockId,
295293
}
296294

@@ -337,7 +335,7 @@ fn rwlock_get_data<'tcx>(
337335
)? {
338336
throw_unsup_format!("unsupported static initializer used for `pthread_rwlock_t`");
339337
}
340-
let id = ecx.rwlock_create();
338+
let id = ecx.machine.sync.rwlock_create();
341339
let data = RwLockData { id };
342340
sync_init(ecx, &rwlock, init_offset, data)?;
343341
interp_ok(data)
@@ -446,7 +444,7 @@ fn cond_create<'tcx>(
446444
clock: ClockId,
447445
) -> InterpResult<'tcx, CondData> {
448446
let cond = ecx.deref_pointer(cond_ptr)?;
449-
let id = ecx.condvar_create();
447+
let id = ecx.machine.sync.condvar_create();
450448
let data = CondData { id, clock };
451449
sync_init(ecx, &cond, cond_init_offset(ecx)?, data)?;
452450
interp_ok(data)

0 commit comments

Comments
 (0)