Skip to content

Commit 218057c

Browse files
committed
sync: store extra sync primitive data in a Box<dyn Any> so the type can be kept local
1 parent 51dbed2 commit 218057c

File tree

3 files changed

+59
-66
lines changed

3 files changed

+59
-66
lines changed

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

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::any::Any;
12
use std::collections::{hash_map::Entry, VecDeque};
23
use std::ops::Not;
34
use std::time::Duration;
@@ -66,27 +67,6 @@ pub(super) use declare_id;
6667

6768
declare_id!(MutexId);
6869

69-
/// The mutex kind.
70-
#[derive(Debug, Clone, Copy)]
71-
#[non_exhaustive]
72-
pub enum MutexKind {
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-
pub struct AdditionalMutexData {
83-
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
84-
pub kind: MutexKind,
85-
86-
/// The address of the mutex.
87-
pub address: u64,
88-
}
89-
9070
/// The mutex state.
9171
#[derive(Default, Debug)]
9272
struct Mutex {
@@ -100,18 +80,11 @@ struct Mutex {
10080
clock: VClock,
10181

10282
/// Additional data that can be set by shim implementations.
103-
data: Option<AdditionalMutexData>,
83+
data: Option<Box<dyn Any>>,
10484
}
10585

10686
declare_id!(RwLockId);
10787

108-
#[derive(Debug)]
109-
/// Additional data that may be used by shim implementations.
110-
pub struct AdditionalRwLockData {
111-
/// The address of the rwlock.
112-
pub address: u64,
113-
}
114-
11588
/// The read-write lock state.
11689
#[derive(Default, Debug)]
11790
struct RwLock {
@@ -146,7 +119,7 @@ struct RwLock {
146119
clock_current_readers: VClock,
147120

148121
/// Additional data that can be set by shim implementations.
149-
data: Option<AdditionalRwLockData>,
122+
data: Option<Box<dyn Any>>,
150123
}
151124

152125
declare_id!(CondvarId);
@@ -304,7 +277,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
304277
&mut self,
305278
lock: &MPlaceTy<'tcx>,
306279
offset: u64,
307-
data: Option<AdditionalMutexData>,
280+
data: Option<Box<dyn Any>>,
308281
) -> InterpResult<'tcx, MutexId> {
309282
let this = self.eval_context_mut();
310283
this.create_id(
@@ -323,7 +296,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
323296
offset: u64,
324297
initialize_data: impl for<'a> FnOnce(
325298
&'a mut MiriInterpCx<'tcx>,
326-
) -> InterpResult<'tcx, Option<AdditionalMutexData>>,
299+
) -> InterpResult<'tcx, Option<Box<dyn Any>>>,
327300
) -> InterpResult<'tcx, MutexId> {
328301
let this = self.eval_context_mut();
329302
this.get_or_create_id(
@@ -336,12 +309,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
336309
}
337310

338311
/// Retrieve the additional data stored for a mutex.
339-
fn mutex_get_data<'a>(&'a mut self, id: MutexId) -> Option<&'a AdditionalMutexData>
312+
fn mutex_get_data<'a, T: 'static>(&'a mut self, id: MutexId) -> Option<&'a T>
340313
where
341314
'tcx: 'a,
342315
{
343316
let this = self.eval_context_ref();
344-
this.machine.sync.mutexes[id].data.as_ref()
317+
this.machine.sync.mutexes[id].data.as_deref().and_then(|p| p.downcast_ref::<T>())
345318
}
346319

347320
fn rwlock_get_or_create_id(
@@ -350,8 +323,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
350323
offset: u64,
351324
initialize_data: impl for<'a> FnOnce(
352325
&'a mut MiriInterpCx<'tcx>,
353-
)
354-
-> InterpResult<'tcx, Option<AdditionalRwLockData>>,
326+
) -> InterpResult<'tcx, Option<Box<dyn Any>>>,
355327
) -> InterpResult<'tcx, RwLockId> {
356328
let this = self.eval_context_mut();
357329
this.get_or_create_id(
@@ -364,12 +336,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
364336
}
365337

366338
/// Retrieve the additional data stored for a rwlock.
367-
fn rwlock_get_data<'a>(&'a mut self, id: RwLockId) -> Option<&'a AdditionalRwLockData>
339+
fn rwlock_get_data<'a, T: 'static>(&'a mut self, id: RwLockId) -> Option<&'a T>
368340
where
369341
'tcx: 'a,
370342
{
371343
let this = self.eval_context_ref();
372-
this.machine.sync.rwlocks[id].data.as_ref()
344+
this.machine.sync.rwlocks[id].data.as_deref().and_then(|p| p.downcast_ref::<T>())
373345
}
374346

375347
fn condvar_get_or_create_id(

src/tools/miri/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ pub use crate::concurrency::{
133133
cpu_affinity::MAX_CPUS,
134134
data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
135135
init_once::{EvalContextExt as _, InitOnceId},
136-
sync::{
137-
AdditionalMutexData, AdditionalRwLockData, CondvarId, EvalContextExt as _, MutexId,
138-
MutexKind, RwLockId, SynchronizationObjects,
139-
},
136+
sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects},
140137
thread::{
141138
BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager,
142139
TimeoutAnchor, TimeoutClock, UnblockCallback,

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

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,25 @@ fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResu
5959
Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG))
6060
}
6161

62+
/// The mutex kind.
63+
#[derive(Debug, Clone, Copy)]
64+
pub enum MutexKind {
65+
Normal,
66+
Default,
67+
Recursive,
68+
ErrorCheck,
69+
}
70+
71+
#[derive(Debug)]
72+
/// Additional data that we attach with each mutex instance.
73+
pub struct AdditionalMutexData {
74+
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
75+
pub kind: MutexKind,
76+
77+
/// The address of the mutex.
78+
pub address: u64,
79+
}
80+
6281
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
6382
// We ignore the platform layout and store our own fields:
6483
// - id: u32
@@ -100,8 +119,8 @@ fn mutex_create<'tcx>(
100119
let mutex = ecx.deref_pointer(mutex_ptr)?;
101120
let address = mutex.ptr().addr().bytes();
102121
let kind = translate_kind(ecx, kind)?;
103-
let data = Some(AdditionalMutexData { address, kind });
104-
ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, data)?;
122+
let data = Box::new(AdditionalMutexData { address, kind });
123+
ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?;
105124
Ok(())
106125
}
107126

@@ -121,11 +140,13 @@ fn mutex_get_id<'tcx>(
121140
// an ID yet. We have to determine the mutex kind from the static initializer.
122141
let kind = kind_from_static_initializer(ecx, &mutex)?;
123142

124-
Ok(Some(AdditionalMutexData { kind, address }))
143+
Ok(Some(Box::new(AdditionalMutexData { kind, address })))
125144
})?;
126145

127146
// Check that the mutex has not been moved since last use.
128-
let data = ecx.mutex_get_data(id).expect("data should be always exist for pthreads");
147+
let data = ecx
148+
.mutex_get_data::<AdditionalMutexData>(id)
149+
.expect("data should always exist for pthreads");
129150
if data.address != address {
130151
throw_ub_format!("pthread_mutex_t can't be moved after first use")
131152
}
@@ -171,6 +192,13 @@ fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tc
171192
// We ignore the platform layout and store our own fields:
172193
// - id: u32
173194

195+
#[derive(Debug)]
196+
/// Additional data that may be used by shim implementations.
197+
pub struct AdditionalRwLockData {
198+
/// The address of the rwlock.
199+
pub address: u64,
200+
}
201+
174202
fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
175203
let offset = match &*ecx.tcx.sess.target.os {
176204
"linux" | "illumos" | "solaris" => 0,
@@ -205,11 +233,13 @@ fn rwlock_get_id<'tcx>(
205233
let address = rwlock.ptr().addr().bytes();
206234

207235
let id = ecx.rwlock_get_or_create_id(&rwlock, rwlock_id_offset(ecx)?, |_| {
208-
Ok(Some(AdditionalRwLockData { address }))
236+
Ok(Some(Box::new(AdditionalRwLockData { address })))
209237
})?;
210238

211239
// Check that the rwlock has not been moved since last use.
212-
let data = ecx.rwlock_get_data(id).expect("data should be always exist for pthreads");
240+
let data = ecx
241+
.rwlock_get_data::<AdditionalRwLockData>(id)
242+
.expect("data should always exist for pthreads");
213243
if data.address != address {
214244
throw_ub_format!("pthread_rwlock_t can't be moved after first use")
215245
}
@@ -473,8 +503,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
473503
let this = self.eval_context_mut();
474504

475505
let id = mutex_get_id(this, mutex_op)?;
476-
let kind =
477-
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
506+
let kind = this
507+
.mutex_get_data::<AdditionalMutexData>(id)
508+
.expect("data should always exist for pthread mutexes")
509+
.kind;
478510

479511
let ret = if this.mutex_is_locked(id) {
480512
let owner_thread = this.mutex_get_owner(id);
@@ -492,10 +524,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
492524
this.mutex_lock(id);
493525
0
494526
}
495-
_ =>
496-
throw_unsup_format!(
497-
"called pthread_mutex_lock on an unsupported type of mutex"
498-
),
499527
}
500528
}
501529
} else {
@@ -511,8 +539,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
511539
let this = self.eval_context_mut();
512540

513541
let id = mutex_get_id(this, mutex_op)?;
514-
let kind =
515-
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
542+
let kind = this
543+
.mutex_get_data::<AdditionalMutexData>(id)
544+
.expect("data should always exist for pthread mutexes")
545+
.kind;
516546

517547
Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
518548
let owner_thread = this.mutex_get_owner(id);
@@ -526,10 +556,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
526556
this.mutex_lock(id);
527557
0
528558
}
529-
_ =>
530-
throw_unsup_format!(
531-
"called pthread_mutex_trylock on an unsupported type of mutex"
532-
),
533559
}
534560
}
535561
} else {
@@ -543,8 +569,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
543569
let this = self.eval_context_mut();
544570

545571
let id = mutex_get_id(this, mutex_op)?;
546-
let kind =
547-
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
572+
let kind = this
573+
.mutex_get_data::<AdditionalMutexData>(id)
574+
.expect("data should always exist for pthread mutexes")
575+
.kind;
548576

549577
if let Some(_old_locked_count) = this.mutex_unlock(id)? {
550578
// The mutex was locked by the current thread.
@@ -564,10 +592,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
564592
),
565593
MutexKind::ErrorCheck | MutexKind::Recursive =>
566594
Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))),
567-
_ =>
568-
throw_unsup_format!(
569-
"called pthread_mutex_unlock on an unsupported type of mutex"
570-
),
571595
}
572596
}
573597
}

0 commit comments

Comments
 (0)