@@ -288,15 +288,12 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>(
288288 active_thread : ThreadId ,
289289 mutex : MutexId ,
290290) -> InterpResult < ' tcx > {
291- if let Some ( ( old_owner_thread , old_locked_count) ) = ecx. mutex_unlock ( mutex) ? {
291+ if let Some ( old_locked_count) = ecx. mutex_unlock ( mutex, active_thread ) ? {
292292 if old_locked_count != 1 {
293293 throw_unsup_format ! ( "awaiting on a lock acquired multiple times is not supported" ) ;
294294 }
295- if old_owner_thread != active_thread {
296- throw_ub_format ! ( "awaiting on a mutex owned by a different thread" ) ;
297- }
298295 } else {
299- throw_ub_format ! ( "awaiting on unlocked mutex" ) ;
296+ throw_ub_format ! ( "awaiting on unlocked or owned by a different thread mutex" ) ;
300297 }
301298 ecx. block_thread ( active_thread) ?;
302299 Ok ( ( ) )
@@ -321,7 +318,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
321318 let this = self . eval_context_mut ( ) ;
322319
323320 let kind = this. read_scalar ( kind_op) ?. not_undef ( ) ?;
324- if kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ?
321+ if kind == this. eval_libc ( "PTHREAD_MUTEX_DEFAULT" ) ?
322+ || kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ?
325323 || kind == this. eval_libc ( "PTHREAD_MUTEX_ERRORCHECK" ) ?
326324 || kind == this. eval_libc ( "PTHREAD_MUTEX_RECURSIVE" ) ?
327325 {
@@ -380,6 +378,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
380378 Ok ( 0 )
381379 } else {
382380 // Trying to acquire the same mutex again.
381+ if kind == this. eval_libc ( "PTHREAD_MUTEX_DEFAULT" ) ? {
382+ // FIXME: Sometimes this is actually a Deadlock.
383+ // https://github.com/rust-lang/miri/issues/1419
384+ throw_ub_format ! (
385+ "trying to acquire already locked PTHREAD_MUTEX_DEFAULT (see #1419)"
386+ ) ;
387+ }
383388 if kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ? {
384389 throw_machine_stop ! ( TerminationInfo :: Deadlock ) ;
385390 } else if kind == this. eval_libc ( "PTHREAD_MUTEX_ERRORCHECK" ) ? {
@@ -388,7 +393,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
388393 this. mutex_lock ( id, active_thread) ;
389394 Ok ( 0 )
390395 } else {
391- throw_ub_format ! ( "called pthread_mutex_lock on an unsupported type of mutex" ) ;
396+ throw_unsup_format ! (
397+ "called pthread_mutex_lock on an unsupported type of mutex"
398+ ) ;
392399 }
393400 }
394401 } else {
@@ -410,15 +417,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
410417 if owner_thread != active_thread {
411418 this. eval_libc_i32 ( "EBUSY" )
412419 } else {
413- if kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ?
420+ if kind == this. eval_libc ( "PTHREAD_MUTEX_DEFAULT" ) ?
421+ || kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ?
414422 || kind == this. eval_libc ( "PTHREAD_MUTEX_ERRORCHECK" ) ?
415423 {
416424 this. eval_libc_i32 ( "EBUSY" )
417425 } else if kind == this. eval_libc ( "PTHREAD_MUTEX_RECURSIVE" ) ? {
418426 this. mutex_lock ( id, active_thread) ;
419427 Ok ( 0 )
420428 } else {
421- throw_ub_format ! (
429+ throw_unsup_format ! (
422430 "called pthread_mutex_trylock on an unsupported type of mutex"
423431 ) ;
424432 }
@@ -435,21 +443,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
435443
436444 let kind = mutex_get_kind ( this, mutex_op) ?. not_undef ( ) ?;
437445 let id = mutex_get_or_create_id ( this, mutex_op) ?;
446+ let active_thread = this. get_active_thread ( ) ?;
438447
439- if let Some ( ( old_owner_thread, _old_locked_count) ) = this. mutex_unlock ( id) ? {
440- if old_owner_thread != this. get_active_thread ( ) ? {
441- throw_ub_format ! ( "called pthread_mutex_unlock on a mutex owned by another thread" ) ;
442- }
448+ if let Some ( _old_locked_count) = this. mutex_unlock ( id, active_thread) ? {
449+ // The mutex was locked by the current thread.
443450 Ok ( 0 )
444451 } else {
445- if kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ? {
446- throw_ub_format ! ( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked" ) ;
452+ // The mutex was locked by another thread or not locked at all. See
453+ // the “Unlock When Not Owner” column in
454+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html.
455+ if kind == this. eval_libc ( "PTHREAD_MUTEX_DEFAULT" ) ? {
456+ throw_ub_format ! (
457+ "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread"
458+ ) ;
459+ } else if kind == this. eval_libc ( "PTHREAD_MUTEX_NORMAL" ) ? {
460+ throw_ub_format ! (
461+ "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread"
462+ ) ;
447463 } else if kind == this. eval_libc ( "PTHREAD_MUTEX_ERRORCHECK" ) ? {
448464 this. eval_libc_i32 ( "EPERM" )
449465 } else if kind == this. eval_libc ( "PTHREAD_MUTEX_RECURSIVE" ) ? {
450466 this. eval_libc_i32 ( "EPERM" )
451467 } else {
452- throw_ub_format ! ( "called pthread_mutex_unlock on an unsupported type of mutex" ) ;
468+ throw_unsup_format ! ( "called pthread_mutex_unlock on an unsupported type of mutex" ) ;
453469 }
454470 }
455471 }
@@ -505,6 +521,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
505521 let active_thread = this. get_active_thread ( ) ?;
506522
507523 if this. rwlock_is_locked ( id) {
524+ // Note: this will deadlock if the lock is already locked by this
525+ // thread in any way.
526+ //
527+ // Relevant documentation:
528+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html
529+ // An in depth discussion on this topic:
530+ // https://github.com/rust-lang/rust/issues/53127
531+ //
532+ // FIXME: Detect and report the deadlock proactively. (We currently
533+ // report the deadlock only when no thread can continue execution,
534+ // but we could detect that this lock is already locked and report
535+ // an error.)
508536 this. rwlock_enqueue_and_block_writer ( id, active_thread) ?;
509537 } else {
510538 this. rwlock_writer_lock ( id, active_thread) ;
@@ -719,19 +747,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
719747 let clock_id = cond_get_clock_id ( this, cond_op) ?. to_i32 ( ) ?;
720748 let duration = {
721749 let tp = this. deref_operand ( abstime_op) ?;
722- let mut offset = Size :: from_bytes ( 0 ) ;
723- let layout = this. libc_ty_layout ( "time_t" ) ?;
724- let seconds_place = tp. offset ( offset, MemPlaceMeta :: None , layout, this) ?;
750+ let seconds_place = this. mplace_field ( tp, 0 ) ?;
725751 let seconds = this. read_scalar ( seconds_place. into ( ) ) ?;
726- offset += layout. size ;
727- let layout = this. libc_ty_layout ( "c_long" ) ?;
728- let nanoseconds_place = tp. offset ( offset, MemPlaceMeta :: None , layout, this) ?;
752+ let nanoseconds_place = this. mplace_field ( tp, 1 ) ?;
729753 let nanoseconds = this. read_scalar ( nanoseconds_place. into ( ) ) ?;
730- let ( seconds, nanoseconds) = if this. pointer_size ( ) . bytes ( ) == 8 {
731- ( seconds. to_u64 ( ) ?, nanoseconds. to_u64 ( ) ?. try_into ( ) . unwrap ( ) )
732- } else {
733- ( seconds. to_u32 ( ) ?. into ( ) , nanoseconds. to_u32 ( ) ?)
734- } ;
754+ let ( seconds, nanoseconds) = (
755+ seconds. to_machine_usize ( this) ?,
756+ nanoseconds. to_machine_usize ( this) ?. try_into ( ) . unwrap ( ) ,
757+ ) ;
735758 Duration :: new ( seconds, nanoseconds)
736759 } ;
737760
@@ -740,7 +763,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
740763 } else if clock_id == this. eval_libc_i32 ( "CLOCK_MONOTONIC" ) ? {
741764 Time :: Monotonic ( this. machine . time_anchor . checked_add ( duration) . unwrap ( ) )
742765 } else {
743- throw_unsup_format ! ( "Unsupported clock id." ) ;
766+ throw_unsup_format ! ( "unsupported clock id: {}" , clock_id ) ;
744767 } ;
745768
746769 // Register the timeout callback.
0 commit comments