Skip to content

Commit 424bc60

Browse files
committed
sync support: dont implicitly clone inside the general sync machinery
1 parent 7137683 commit 424bc60

File tree

4 files changed

+64
-38
lines changed

4 files changed

+64
-38
lines changed

src/tools/miri/src/concurrency/sync.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,16 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
221221
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
222222
/// Helper for lazily initialized `alloc_extra.sync` data:
223223
/// this forces an immediate init.
224-
fn lazy_sync_init<T: 'static>(
225-
&mut self,
224+
/// Return a reference to the data in the machine state.
225+
fn lazy_sync_init<'a, T: 'static>(
226+
&'a mut self,
226227
primitive: &MPlaceTy<'tcx>,
227228
init_offset: Size,
228229
data: T,
229-
) -> InterpResult<'tcx> {
230+
) -> InterpResult<'tcx, &'a T>
231+
where
232+
'tcx: 'a,
233+
{
230234
let this = self.eval_context_mut();
231235

232236
let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
@@ -239,7 +243,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
239243
&init_field,
240244
AtomicWriteOrd::Relaxed,
241245
)?;
242-
interp_ok(())
246+
interp_ok(this.get_alloc_extra(alloc)?.get_sync::<T>(offset).unwrap())
243247
}
244248

245249
/// Helper for lazily initialized `alloc_extra.sync` data:
@@ -248,15 +252,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
248252
/// and stores that in `alloc_extra.sync`.
249253
/// - Otherwise, calls `new_data` to initialize the primitive.
250254
///
251-
/// The return value is a *clone* of the stored data, so if you intend to mutate it
252-
/// better wrap everything into an `Rc`.
253-
fn lazy_sync_get_data<T: 'static + Clone>(
254-
&mut self,
255+
/// Return a reference to the data in the machine state.
256+
fn lazy_sync_get_data<'a, T: 'static>(
257+
&'a mut self,
255258
primitive: &MPlaceTy<'tcx>,
256259
init_offset: Size,
257260
missing_data: impl FnOnce() -> InterpResult<'tcx, T>,
258261
new_data: impl FnOnce(&mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
259-
) -> InterpResult<'tcx, T> {
262+
) -> InterpResult<'tcx, &'a T>
263+
where
264+
'tcx: 'a,
265+
{
260266
let this = self.eval_context_mut();
261267

262268
// Check if this is already initialized. Needs to be atomic because we can race with another
@@ -280,17 +286,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
280286
// or else it has been moved illegally.
281287
let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
282288
let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
283-
if let Some(data) = alloc_extra.get_sync::<T>(offset) {
284-
interp_ok(data.clone())
285-
} else {
289+
// Due to borrow checker reasons, we have to do the lookup twice.
290+
if alloc_extra.get_sync::<T>(offset).is_none() {
286291
let data = missing_data()?;
287-
alloc_extra.sync.insert(offset, Box::new(data.clone()));
288-
interp_ok(data)
292+
alloc_extra.sync.insert(offset, Box::new(data));
289293
}
294+
interp_ok(alloc_extra.get_sync::<T>(offset).unwrap())
290295
} else {
291296
let data = new_data(this)?;
292-
this.lazy_sync_init(primitive, init_offset, data.clone())?;
293-
interp_ok(data)
297+
this.lazy_sync_init(primitive, init_offset, data)
294298
}
295299
}
296300

@@ -326,7 +330,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
326330

327331
#[inline]
328332
/// Get the id of the thread that currently owns this lock.
329-
fn mutex_get_owner(&mut self, mutex_ref: &MutexRef) -> ThreadId {
333+
fn mutex_get_owner(&self, mutex_ref: &MutexRef) -> ThreadId {
330334
mutex_ref.0.borrow().owner.unwrap()
331335
}
332336

src/tools/miri/src/shims/unix/macos/sync.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ enum MacOsUnfairLock {
2222

2323
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
2424
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
25-
fn os_unfair_lock_get_data(
26-
&mut self,
25+
fn os_unfair_lock_get_data<'a>(
26+
&'a mut self,
2727
lock_ptr: &OpTy<'tcx>,
28-
) -> InterpResult<'tcx, MacOsUnfairLock> {
28+
) -> InterpResult<'tcx, &'a MacOsUnfairLock>
29+
where
30+
'tcx: 'a,
31+
{
2932
let this = self.eval_context_mut();
3033
let lock = this.deref_pointer(lock_ptr)?;
3134
this.lazy_sync_get_data(
@@ -68,6 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
6871
);
6972
return interp_ok(());
7073
};
74+
let mutex_ref = mutex_ref.clone();
7175

7276
if this.mutex_is_locked(&mutex_ref) {
7377
if this.mutex_get_owner(&mutex_ref) == this.active_thread() {
@@ -97,6 +101,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
97101
this.write_scalar(Scalar::from_bool(false), dest)?;
98102
return interp_ok(());
99103
};
104+
let mutex_ref = mutex_ref.clone();
100105

101106
if this.mutex_is_locked(&mutex_ref) {
102107
// Contrary to the blocking lock function, this does not check for
@@ -119,6 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
119124
"attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
120125
));
121126
};
127+
let mutex_ref = mutex_ref.clone();
122128

123129
// Now, unlock.
124130
if this.mutex_unlock(&mutex_ref)?.is_none() {
@@ -147,6 +153,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
147153
"called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
148154
));
149155
};
156+
let mutex_ref = mutex_ref.clone();
157+
150158
if !this.mutex_is_locked(&mutex_ref)
151159
|| this.mutex_get_owner(&mutex_ref) != this.active_thread()
152160
{
@@ -167,6 +175,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
167175
// The lock is poisoned, who knows who owns it... we'll pretend: someone else.
168176
return interp_ok(());
169177
};
178+
let mutex_ref = mutex_ref.clone();
179+
170180
if this.mutex_is_locked(&mutex_ref)
171181
&& this.mutex_get_owner(&mutex_ref) == this.active_thread()
172182
{

src/tools/miri/src/shims/unix/sync.rs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,10 @@ fn mutex_create<'tcx>(
185185
fn mutex_get_data<'tcx, 'a>(
186186
ecx: &'a mut MiriInterpCx<'tcx>,
187187
mutex_ptr: &OpTy<'tcx>,
188-
) -> InterpResult<'tcx, PthreadMutex> {
188+
) -> InterpResult<'tcx, &'a PthreadMutex>
189+
where
190+
'tcx: 'a,
191+
{
189192
let mutex = ecx.deref_pointer(mutex_ptr)?;
190193
ecx.lazy_sync_get_data(
191194
&mutex,
@@ -259,10 +262,13 @@ fn rwlock_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size
259262
interp_ok(offset)
260263
}
261264

262-
fn rwlock_get_data<'tcx>(
263-
ecx: &mut MiriInterpCx<'tcx>,
265+
fn rwlock_get_data<'tcx, 'a>(
266+
ecx: &'a mut MiriInterpCx<'tcx>,
264267
rwlock_ptr: &OpTy<'tcx>,
265-
) -> InterpResult<'tcx, PthreadRwLock> {
268+
) -> InterpResult<'tcx, &'a PthreadRwLock>
269+
where
270+
'tcx: 'a,
271+
{
266272
let rwlock = ecx.deref_pointer(rwlock_ptr)?;
267273
ecx.lazy_sync_get_data(
268274
&rwlock,
@@ -389,10 +395,13 @@ fn cond_create<'tcx>(
389395
interp_ok(data)
390396
}
391397

392-
fn cond_get_data<'tcx>(
393-
ecx: &mut MiriInterpCx<'tcx>,
398+
fn cond_get_data<'tcx, 'a>(
399+
ecx: &'a mut MiriInterpCx<'tcx>,
394400
cond_ptr: &OpTy<'tcx>,
395-
) -> InterpResult<'tcx, PthreadCondvar> {
401+
) -> InterpResult<'tcx, &'a PthreadCondvar>
402+
where
403+
'tcx: 'a,
404+
{
396405
let cond = ecx.deref_pointer(cond_ptr)?;
397406
ecx.lazy_sync_get_data(
398407
&cond,
@@ -498,7 +507,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
498507
) -> InterpResult<'tcx> {
499508
let this = self.eval_context_mut();
500509

501-
let mutex = mutex_get_data(this, mutex_op)?;
510+
let mutex = mutex_get_data(this, mutex_op)?.clone();
502511

503512
let ret = if this.mutex_is_locked(&mutex.mutex_ref) {
504513
let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
@@ -535,7 +544,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
535544
fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
536545
let this = self.eval_context_mut();
537546

538-
let mutex = mutex_get_data(this, mutex_op)?;
547+
let mutex = mutex_get_data(this, mutex_op)?.clone();
539548

540549
interp_ok(Scalar::from_i32(if this.mutex_is_locked(&mutex.mutex_ref) {
541550
let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
@@ -561,7 +570,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
561570
fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
562571
let this = self.eval_context_mut();
563572

564-
let mutex = mutex_get_data(this, mutex_op)?;
573+
let mutex = mutex_get_data(this, mutex_op)?.clone();
565574

566575
if let Some(_old_locked_count) = this.mutex_unlock(&mutex.mutex_ref)? {
567576
// The mutex was locked by the current thread.
@@ -590,7 +599,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
590599

591600
// Reading the field also has the side-effect that we detect double-`destroy`
592601
// since we make the field unint below.
593-
let mutex = mutex_get_data(this, mutex_op)?;
602+
let mutex = mutex_get_data(this, mutex_op)?.clone();
594603

595604
if this.mutex_is_locked(&mutex.mutex_ref) {
596605
throw_ub_format!("destroyed a locked mutex");
@@ -822,8 +831,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
822831
) -> InterpResult<'tcx> {
823832
let this = self.eval_context_mut();
824833

825-
let data = cond_get_data(this, cond_op)?;
826-
let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref;
834+
let data = *cond_get_data(this, cond_op)?;
835+
let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
827836

828837
this.condvar_wait(
829838
data.id,
@@ -846,8 +855,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
846855
) -> InterpResult<'tcx> {
847856
let this = self.eval_context_mut();
848857

849-
let data = cond_get_data(this, cond_op)?;
850-
let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref;
858+
let data = *cond_get_data(this, cond_op)?;
859+
let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
851860

852861
// Extract the timeout.
853862
let duration = match this

src/tools/miri/src/shims/windows/sync.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
2020
// Windows sync primitives are pointer sized.
2121
// We only use the first 4 bytes for the id.
2222

23-
fn init_once_get_data(
24-
&mut self,
23+
fn init_once_get_data<'a>(
24+
&'a mut self,
2525
init_once_ptr: &OpTy<'tcx>,
26-
) -> InterpResult<'tcx, WindowsInitOnce> {
26+
) -> InterpResult<'tcx, &'a WindowsInitOnce>
27+
where
28+
'tcx: 'a,
29+
{
2730
let this = self.eval_context_mut();
2831

2932
let init_once = this.deref_pointer(init_once_ptr)?;

0 commit comments

Comments
 (0)