Skip to content

Commit efdc01b

Browse files
committed
unix/sync: cleanup
1 parent 8c4f055 commit efdc01b

File tree

1 file changed

+29
-81
lines changed
  • src/tools/miri/src/shims/unix

1 file changed

+29
-81
lines changed

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

Lines changed: 29 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,6 @@ fn mutexattr_set_kind<'tcx>(
5050
/// in `pthread_mutexattr_settype` function.
5151
const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000;
5252

53-
fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
54-
Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"))
55-
}
56-
57-
fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> {
58-
let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL");
59-
Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG))
60-
}
61-
6253
/// The mutex kind.
6354
#[derive(Debug, Clone, Copy)]
6455
pub enum MutexKind {
@@ -78,7 +69,7 @@ pub struct AdditionalMutexData {
7869
pub address: u64,
7970
}
8071

81-
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
72+
// pthread_mutex_t is between 4 and 48 bytes, depending on the platform.
8273
// We ignore the platform layout and store our own fields:
8374
// - id: u32
8475

@@ -131,7 +122,7 @@ fn mutex_create<'tcx>(
131122
) -> InterpResult<'tcx> {
132123
let mutex = ecx.deref_pointer(mutex_ptr)?;
133124
let address = mutex.ptr().addr().bytes();
134-
let kind = translate_kind(ecx, kind)?;
125+
let kind = mutex_translate_kind(ecx, kind)?;
135126
let data = Box::new(AdditionalMutexData { address, kind });
136127
ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?;
137128
Ok(())
@@ -151,7 +142,7 @@ fn mutex_get_id<'tcx>(
151142
let id = ecx.mutex_get_or_create_id(&mutex, mutex_id_offset(ecx)?, |ecx| {
152143
// This is called if a static initializer was used and the lock has not been assigned
153144
// an ID yet. We have to determine the mutex kind from the static initializer.
154-
let kind = kind_from_static_initializer(ecx, &mutex)?;
145+
let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
155146

156147
Ok(Some(Box::new(AdditionalMutexData { kind, address })))
157148
})?;
@@ -168,12 +159,12 @@ fn mutex_get_id<'tcx>(
168159
}
169160

170161
/// Returns the kind of a static initializer.
171-
fn kind_from_static_initializer<'tcx>(
162+
fn mutex_kind_from_static_initializer<'tcx>(
172163
ecx: &MiriInterpCx<'tcx>,
173164
mutex: &MPlaceTy<'tcx>,
174165
) -> InterpResult<'tcx, MutexKind> {
175-
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
176166
let kind = match &*ecx.tcx.sess.target.os {
167+
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
177168
"linux" => {
178169
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
179170
let kind_place =
@@ -184,13 +175,16 @@ fn kind_from_static_initializer<'tcx>(
184175
os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
185176
};
186177

187-
translate_kind(ecx, kind)
178+
mutex_translate_kind(ecx, kind)
188179
}
189180

190-
fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, MutexKind> {
191-
Ok(if is_mutex_kind_default(ecx, kind)? {
181+
fn mutex_translate_kind<'tcx>(
182+
ecx: &MiriInterpCx<'tcx>,
183+
kind: i32,
184+
) -> InterpResult<'tcx, MutexKind> {
185+
Ok(if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT") {
192186
MutexKind::Default
193-
} else if is_mutex_kind_normal(ecx, kind)? {
187+
} else if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL") | PTHREAD_MUTEX_NORMAL_FLAG) {
194188
MutexKind::Normal
195189
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
196190
MutexKind::ErrorCheck
@@ -201,7 +195,7 @@ fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tc
201195
})
202196
}
203197

204-
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
198+
// pthread_rwlock_t is between 4 and 56 bytes, depending on the platform.
205199
// We ignore the platform layout and store our own fields:
206200
// - id: u32
207201

@@ -286,11 +280,11 @@ fn condattr_get_clock_id<'tcx>(
286280
.to_i32()
287281
}
288282

289-
fn translate_clock_id<'tcx>(ecx: &MiriInterpCx<'tcx>, raw_id: i32) -> InterpResult<'tcx, ClockId> {
290-
// To ensure compatibility with PTHREAD_COND_INITIALIZER on all platforms,
291-
// we can't just compare with CLOCK_REALTIME: on Solarish, PTHREAD_COND_INITIALIZER
292-
// makes the clock 0 but CLOCK_REALTIME is 3.
293-
Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") || raw_id == 0 {
283+
fn cond_translate_clock_id<'tcx>(
284+
ecx: &MiriInterpCx<'tcx>,
285+
raw_id: i32,
286+
) -> InterpResult<'tcx, ClockId> {
287+
Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
294288
ClockId::Realtime
295289
} else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
296290
ClockId::Monotonic
@@ -313,10 +307,9 @@ fn condattr_set_clock_id<'tcx>(
313307
)
314308
}
315309

316-
// pthread_cond_t.
310+
// pthread_cond_t can be only 4 bytes in size, depending on the platform.
317311
// We ignore the platform layout and store our own fields:
318312
// - id: u32
319-
// - clock: i32
320313

321314
fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
322315
let offset = match &*ecx.tcx.sess.target.os {
@@ -344,30 +337,6 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
344337
Ok(offset)
345338
}
346339

347-
fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
348-
// macOS doesn't have a clock attribute, but to keep the code uniform we store
349-
// a clock ID in the pthread_cond_t anyway. There's enough space.
350-
let offset = 8;
351-
352-
// Sanity-check this against PTHREAD_COND_INITIALIZER (but only once):
353-
// the clock must start out as CLOCK_REALTIME.
354-
static SANITY: AtomicBool = AtomicBool::new(false);
355-
if !SANITY.swap(true, Ordering::Relaxed) {
356-
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_COND_INITIALIZER"]);
357-
let id_field = static_initializer
358-
.offset(Size::from_bytes(offset), ecx.machine.layouts.i32, ecx)
359-
.unwrap();
360-
let id = ecx.read_scalar(&id_field).unwrap().to_i32().unwrap();
361-
let id = translate_clock_id(ecx, id).expect("static initializer should be valid");
362-
assert!(
363-
matches!(id, ClockId::Realtime),
364-
"PTHREAD_COND_INITIALIZER is incompatible with our pthread_cond layout: clock is not CLOCK_REALTIME"
365-
);
366-
}
367-
368-
offset
369-
}
370-
371340
#[derive(Debug, Clone, Copy)]
372341
enum ClockId {
373342
Realtime,
@@ -390,14 +359,9 @@ fn cond_get_id<'tcx>(
390359
) -> InterpResult<'tcx, CondvarId> {
391360
let cond = ecx.deref_pointer(cond_ptr)?;
392361
let address = cond.ptr().addr().bytes();
393-
let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |ecx| {
394-
let raw_id = if ecx.tcx.sess.target.os == "macos" {
395-
ecx.eval_libc_i32("CLOCK_REALTIME")
396-
} else {
397-
cond_get_clock_id(ecx, cond_ptr)?
398-
};
399-
let clock_id = translate_clock_id(ecx, raw_id)?;
400-
Ok(Some(Box::new(AdditionalCondData { address, clock_id })))
362+
let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| {
363+
// This used the static initializer. The clock there is always CLOCK_REALTIME.
364+
Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime })))
401365
})?;
402366

403367
// Check that the mutex has not been moved since last use.
@@ -411,19 +375,6 @@ fn cond_get_id<'tcx>(
411375
Ok(id)
412376
}
413377

414-
fn cond_get_clock_id<'tcx>(
415-
ecx: &MiriInterpCx<'tcx>,
416-
cond_ptr: &OpTy<'tcx>,
417-
) -> InterpResult<'tcx, i32> {
418-
ecx.deref_pointer_and_read(
419-
cond_ptr,
420-
cond_clock_offset(ecx),
421-
ecx.libc_ty_layout("pthread_cond_t"),
422-
ecx.machine.layouts.i32,
423-
)?
424-
.to_i32()
425-
}
426-
427378
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
428379
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
429380
fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -624,15 +575,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
624575
fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
625576
let this = self.eval_context_mut();
626577

578+
// Reading the field also has the side-effect that we detect double-`destroy`
579+
// since we make the field unint below.
627580
let id = mutex_get_id(this, mutex_op)?;
628581

629582
if this.mutex_is_locked(id) {
630583
throw_ub_format!("destroyed a locked mutex");
631584
}
632585

633-
// Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
634-
mutex_get_id(this, mutex_op)?;
635-
636586
// This might lead to false positives, see comment in pthread_mutexattr_destroy
637587
this.write_uninit(
638588
&this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
@@ -734,15 +684,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
734684
fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
735685
let this = self.eval_context_mut();
736686

687+
// Reading the field also has the side-effect that we detect double-`destroy`
688+
// since we make the field unint below.
737689
let id = rwlock_get_id(this, rwlock_op)?;
738690

739691
if this.rwlock_is_locked(id) {
740692
throw_ub_format!("destroyed a locked rwlock");
741693
}
742694

743-
// Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit.
744-
rwlock_get_id(this, rwlock_op)?;
745-
746695
// This might lead to false positives, see comment in pthread_mutexattr_destroy
747696
this.write_uninit(
748697
&this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
@@ -832,7 +781,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
832781
} else {
833782
condattr_get_clock_id(this, attr_op)?
834783
};
835-
let clock_id = translate_clock_id(this, clock_id)?;
784+
let clock_id = cond_translate_clock_id(this, clock_id)?;
836785

837786
let cond = this.deref_pointer(cond_op)?;
838787
let address = cond.ptr().addr().bytes();
@@ -930,11 +879,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
930879
}
931880

932881
fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
933-
//NOTE: Destroying an uninit pthread_cond is UB. Make sure it's not uninit,
934-
// by accessing at least once all of its fields that we use.
935-
936882
let this = self.eval_context_mut();
937883

884+
// Reading the field also has the side-effect that we detect double-`destroy`
885+
// since we make the field unint below.
938886
let id = cond_get_id(this, cond_op)?;
939887
if this.condvar_is_awaited(id) {
940888
throw_ub_format!("destroying an awaited conditional variable");

0 commit comments

Comments
 (0)