Skip to content

Commit 5f22103

Browse files
committed
Detect pthread_mutex_t is moved
See: #3749
1 parent ad7a1aa commit 5f22103

8 files changed

Lines changed: 310 additions & 116 deletions

File tree

‎src/tools/miri/src/concurrency/init_once.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
3535
offset:u64,
3636
) -> InterpResult<'tcx,InitOnceId>{
3737
let this = self.eval_context_mut();
38-
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.init_onces)?
39-
.ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
38+
this.get_or_create_id(
39+
lock_op,
40+
lock_layout,
41+
offset,
42+
|ecx| &mut ecx.machine.sync.init_onces,
43+
|_| Ok(Default::default()),
44+
)?
45+
.ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
4046
}
4147

4248
#[inline]

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

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ pub(super) use declare_id;
6666

6767
declare_id!(MutexId);
6868

69+
/// The mutex kind.
70+
#[derive(Debug,Clone,Copy)]
71+
#[non_exhaustive]
72+
pubenumMutexKind{
73+
Invalid,
74+
Normal,
75+
Default,
76+
Recursive,
77+
ErrorCheck,
78+
}
79+
80+
#[derive(Debug)]
81+
/// Additional data that may be used by shim implementations.
82+
pubstructAdditionalMutexData{
83+
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
84+
pubkind:MutexKind,
85+
86+
/// The address of the mutex.
87+
pubaddress:u64,
88+
}
89+
6990
/// The mutex state.
7091
#[derive(Default,Debug)]
7192
structMutex{
@@ -77,6 +98,9 @@ struct Mutex {
7798
queue:VecDeque<ThreadId>,
7899
/// Mutex clock. This tracks the moment of the last unlock.
79100
clock:VClock,
101+
102+
/// Additional data that can be set by shim implementations.
103+
data:Option<AdditionalMutexData>,
80104
}
81105

82106
declare_id!(RwLockId);
@@ -168,13 +192,15 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
168192
/// Returns `None` if memory stores a non-zero invalid ID.
169193
///
170194
/// `get_objs` must return the `IndexVec` that stores all the objects of this type.
195+
/// `create_obj` must create the new object if initialization is needed.
171196
#[inline]
172-
fnget_or_create_id<Id:SyncId + Idx,T:Default>(
197+
fnget_or_create_id<Id:SyncId + Idx,T>(
173198
&mutself,
174199
lock_op:&OpTy<'tcx>,
175200
lock_layout:TyAndLayout<'tcx>,
176201
offset:u64,
177202
get_objs:implfor<'a>Fn(&'amutMiriInterpCx<'tcx>) -> &'amutIndexVec<Id,T>,
203+
create_obj:implfor<'a>FnOnce(&'amutMiriInterpCx<'tcx>) -> InterpResult<'tcx,T>,
178204
) -> InterpResult<'tcx,Option<Id>>{
179205
let this = self.eval_context_mut();
180206
let value_place =
@@ -196,7 +222,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
196222
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool"){
197223
// We set the in-memory ID to `next_index`, now also create this object in the machine
198224
// state.
199-
let new_index = get_objs(this).push(T::default());
225+
let obj = create_obj(this)?;
226+
let new_index = get_objs(this).push(obj);
200227
assert_eq!(next_index, new_index);
201228
Some(new_index)
202229
}else{
@@ -210,6 +237,32 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
210237
})
211238
}
212239

240+
/// Eagerly creates a Miri sync structure.
241+
///
242+
/// `create_id` will store the index of the sync_structure in the memory pointed to by
243+
/// `lock_op`, so that future calls to `get_or_create_id` will see it as initialized.
244+
/// - `lock_op` must hold a pointer to the sync structure.
245+
/// - `lock_layout` must be the memory layout of the sync structure.
246+
/// - `offset` must be the offset inside the sync structure where its miri id will be stored.
247+
/// - `get_objs` is described in `get_or_create_id`.
248+
/// - `obj` must be the new sync object.
249+
fncreate_id<Id:SyncId + Idx,T>(
250+
&mutself,
251+
lock_op:&OpTy<'tcx>,
252+
lock_layout:TyAndLayout<'tcx>,
253+
offset:u64,
254+
get_objs:implfor<'a>Fn(&'amutMiriInterpCx<'tcx>) -> &'amutIndexVec<Id,T>,
255+
obj:T,
256+
) -> InterpResult<'tcx,Id>{
257+
let this = self.eval_context_mut();
258+
let value_place =
259+
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
260+
261+
let new_index = get_objs(this).push(obj);
262+
this.write_scalar(Scalar::from_u32(new_index.to_u32()),&value_place)?;
263+
Ok(new_index)
264+
}
265+
213266
fncondvar_reacquire_mutex(
214267
&mutself,
215268
mutex:MutexId,
@@ -236,15 +289,53 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
236289
// situations.
237290
impl<'tcx>EvalContextExt<'tcx>forcrate::MiriInterpCx<'tcx>{}
238291
pubtraitEvalContextExt<'tcx>:crate::MiriInterpCxExt<'tcx>{
292+
/// Eagerly create and initialize a new mutex.
293+
fnmutex_create(
294+
&mutself,
295+
lock_op:&OpTy<'tcx>,
296+
lock_layout:TyAndLayout<'tcx>,
297+
offset:u64,
298+
data:Option<AdditionalMutexData>,
299+
) -> InterpResult<'tcx,MutexId>{
300+
let this = self.eval_context_mut();
301+
this.create_id(
302+
lock_op,
303+
lock_layout,
304+
offset,
305+
|ecx| &mut ecx.machine.sync.mutexes,
306+
Mutex{ data, ..Default::default()},
307+
)
308+
}
309+
310+
/// Lazily create a new mutex.
311+
/// `initialize_data` must return any additional data that a user wants to associate with the mutex.
239312
fnmutex_get_or_create_id(
240313
&mutself,
241314
lock_op:&OpTy<'tcx>,
242315
lock_layout:TyAndLayout<'tcx>,
243316
offset:u64,
317+
initialize_data:implfor<'a>FnOnce(
318+
&'amutMiriInterpCx<'tcx>,
319+
) -> InterpResult<'tcx,Option<AdditionalMutexData>>,
244320
) -> InterpResult<'tcx,MutexId>{
245321
let this = self.eval_context_mut();
246-
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.mutexes)?
247-
.ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
322+
this.get_or_create_id(
323+
lock_op,
324+
lock_layout,
325+
offset,
326+
|ecx| &mut ecx.machine.sync.mutexes,
327+
|ecx| initialize_data(ecx).map(|data| Mutex{ data, ..Default::default()}),
328+
)?
329+
.ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
330+
}
331+
332+
/// Retrieve the additional data stored for a mutex.
333+
fnmutex_get_data<'a>(&'amutself,id:MutexId) -> Option<&'aAdditionalMutexData>
334+
where
335+
'tcx:'a,
336+
{
337+
let this = self.eval_context_ref();
338+
this.machine.sync.mutexes[id].data.as_ref()
248339
}
249340

250341
fnrwlock_get_or_create_id(
@@ -254,8 +345,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
254345
offset:u64,
255346
) -> InterpResult<'tcx,RwLockId>{
256347
let this = self.eval_context_mut();
257-
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.rwlocks)?
258-
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
348+
this.get_or_create_id(
349+
lock_op,
350+
lock_layout,
351+
offset,
352+
|ecx| &mut ecx.machine.sync.rwlocks,
353+
|_| Ok(Default::default()),
354+
)?
355+
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
259356
}
260357

261358
fncondvar_get_or_create_id(
@@ -265,8 +362,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
265362
offset:u64,
266363
) -> InterpResult<'tcx,CondvarId>{
267364
let this = self.eval_context_mut();
268-
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.condvars)?
269-
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
365+
this.get_or_create_id(
366+
lock_op,
367+
lock_layout,
368+
offset,
369+
|ecx| &mut ecx.machine.sync.condvars,
370+
|_| Ok(Default::default()),
371+
)?
372+
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
270373
}
271374

272375
#[inline]

‎src/tools/miri/src/lib.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,10 @@ pub use crate::concurrency::{
130130
cpu_affinity::MAX_CPUS,
131131
data_race::{AtomicFenceOrd,AtomicReadOrd,AtomicRwOrd,AtomicWriteOrd,EvalContextExtas _},
132132
init_once::{EvalContextExtas _,InitOnceId},
133-
sync::{CondvarId,EvalContextExtas _,MutexId,RwLockId,SynchronizationObjects},
133+
sync::{
134+
AdditionalMutexData,CondvarId,EvalContextExtas _,MutexId,MutexKind,RwLockId,
135+
SynchronizationObjects,
136+
},
134137
thread::{
135138
BlockReason,EvalContextExtas _,StackEmptyCallback,ThreadId,ThreadManager,
136139
TimeoutAnchor,TimeoutClock,UnblockCallback,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
1919
// os_unfair_lock holds a 32-bit value, is initialized with zero and
2020
// must be assumed to be opaque. Therefore, we can just store our
2121
// internal mutex ID in the structure without anyone noticing.
22-
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"),0)
22+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"),0, |_| Ok(None))
2323
}
2424
}
2525

0 commit comments

Comments
 (0)