Skip to content

Commit c7466c9

Browse files
committed
Add TerminationInfo::Deadlock, use in mutex shim
1 parent de29546 commit c7466c9

File tree

2 files changed

+13
-69
lines changed

2 files changed

+13
-69
lines changed

src/diagnostics.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ pub enum TerminationInfo {
1212
Exit(i64),
1313
Abort(Option<String>),
1414
UnsupportedInIsolation(String),
15-
ExperimentalUb { msg: String, url: String }
15+
ExperimentalUb { msg: String, url: String },
16+
Deadlock,
1617
}
1718

1819
impl fmt::Debug for TerminationInfo {
@@ -29,6 +30,8 @@ impl fmt::Debug for TerminationInfo {
2930
write!(f, "{}", msg),
3031
ExperimentalUb { msg, .. } =>
3132
write!(f, "{}", msg),
33+
Deadlock =>
34+
write!(f, "the evaluated program deadlocked"),
3235
}
3336
}
3437
}
@@ -60,6 +63,7 @@ pub fn report_error<'tcx, 'mir>(
6063
"unsupported operation",
6164
ExperimentalUb { .. } =>
6265
"Undefined Behavior",
66+
Deadlock => "deadlock",
6367
};
6468
let helps = match info {
6569
UnsupportedInIsolation(_) =>

src/shims/sync.rs

Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use std::sync::atomic::{AtomicU64, Ordering};
2-
31
use rustc_middle::ty::{TyKind, TypeAndMut};
4-
use rustc_target::abi::{FieldsShape, LayoutOf, Size};
2+
use rustc_target::abi::{LayoutOf, Size};
53

64
use crate::stacked_borrows::Tag;
75
use crate::*;
@@ -102,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
102100
mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?;
103101
Ok(0)
104102
} else {
105-
throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice");
103+
throw_machine_stop!(TerminationInfo::Deadlock);
106104
}
107105
} else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? {
108106
if locked_count == 0 {
@@ -404,58 +402,6 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
404402
// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32
405403
// (the kind has to be at its offset for compatibility with static initializer macros)
406404

407-
static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0);
408-
409-
fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>(
410-
ecx: &mut MiriEvalContext<'mir, 'tcx>,
411-
) -> InterpResult<'tcx, u64> {
412-
// Check if this offset has already been found and memoized
413-
let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed);
414-
if cached_value != 0 {
415-
return Ok(cached_value);
416-
}
417-
418-
// This function infers the offset of the `kind` field of libc's pthread_mutex_t
419-
// C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.
420-
// At time of writing, it is always all zero bytes except for a one byte at one of
421-
// four positions, depending on the target OS's C struct layout and the endianness of the
422-
// target architecture. This offset will then be used in getters and setters below, so that
423-
// mutexes created from static initializers can be emulated with the correct behavior.
424-
let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"];
425-
let initializer_instance = ecx.resolve_path(&initializer_path);
426-
let initializer_cid = GlobalId { instance: initializer_instance, promoted: None };
427-
let initializer_const_val = ecx.const_eval_raw(initializer_cid)?;
428-
let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?;
429-
let array_length = match array_mplacety.layout.fields {
430-
FieldsShape::Array { count, .. } => count,
431-
_ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty),
432-
};
433-
434-
let kind_offset = if array_length < 20 {
435-
bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected");
436-
} else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 {
437-
// for little-endian architectures
438-
16
439-
} else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 {
440-
// for big-endian architectures
441-
// (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16)
442-
16
443-
} else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 {
444-
// for little-endian architectures
445-
12
446-
} else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 {
447-
// for big-endian architectures
448-
// (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12)
449-
12
450-
} else {
451-
bug!("Couldn't determine offset of `kind` in pthread_mutex_t");
452-
};
453-
454-
// Save offset to memoization cache for future calls
455-
LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed);
456-
Ok(kind_offset)
457-
}
458-
459405
fn mutex_get_locked_count<'mir, 'tcx: 'mir>(
460406
ecx: &MiriEvalContext<'mir, 'tcx>,
461407
mutex_op: OpTy<'tcx, Tag>,
@@ -491,12 +437,9 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>(
491437
assert_ptr_target_min_size(ecx, mutex_op, 20)?;
492438
let mutex_place = ecx.deref_operand(mutex_op)?;
493439
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
494-
let kind_place = mutex_place.offset(
495-
Size::from_bytes(libc_mutex_kind_offset(ecx)?),
496-
MemPlaceMeta::None,
497-
i32_layout,
498-
ecx,
499-
)?;
440+
let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
441+
let kind_place =
442+
mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?;
500443
ecx.read_scalar(kind_place.into())
501444
}
502445

@@ -509,12 +452,9 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
509452
assert_ptr_target_min_size(ecx, mutex_op, 20)?;
510453
let mutex_place = ecx.deref_operand(mutex_op)?;
511454
let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?;
512-
let kind_place = mutex_place.offset(
513-
Size::from_bytes(libc_mutex_kind_offset(ecx)?),
514-
MemPlaceMeta::None,
515-
i32_layout,
516-
ecx,
517-
)?;
455+
let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
456+
let kind_place =
457+
mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?;
518458
ecx.write_scalar(kind.into(), kind_place.into())
519459
}
520460

0 commit comments

Comments
 (0)