@@ -20,8 +20,14 @@ use crate::*;
2020
2121#[ derive( Clone ) ]
2222enum MacOsUnfairLock {
23- Active { mutex_ref : MutexRef } ,
24- PermanentlyLocked ,
23+ Active {
24+ mutex_ref : MutexRef ,
25+ } ,
26+ /// If a lock gets copied while being held, we put it in this state.
27+ /// It seems like in the real implementation, the lock actually remembers who held it,
28+ /// and still behaves as-if it was held by that thread in the new location. In Miri, we don't
29+ /// know who actually owns this lock at the moment.
30+ PermanentlyLockedByUnknown ,
2531}
2632
2733impl SyncObj for MacOsUnfairLock {
@@ -93,10 +99,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
9399 // locks when they get released, so it got copied while locked. Unfortunately
94100 // that is something `std` needs to support (the guard could have been leaked).
95101 // On the plus side, we know nobody was queued for the lock while it got copied;
96- // that would have been rejected by our `on_access`. So we behave like a
97- // futex-based lock would in this case: any attempt to acquire the lock will
98- // just wait forever, since there's nobody to wake us up.
99- interp_ok ( MacOsUnfairLock :: PermanentlyLocked )
102+ // that would have been rejected by our `on_access`.
103+ // The real implementation would apparently remember who held the old lock, and
104+ // consider them to hold the copy as well -- but our copies don't preserve sync
105+ // object metadata so we instead move the lock into a "permanently locked"
106+ // state.
107+ interp_ok ( MacOsUnfairLock :: PermanentlyLockedByUnknown )
100108 } else {
101109 throw_ub_format ! ( "`os_unfair_lock` was not properly initialized at this location, or it got overwritten" ) ;
102110 }
@@ -303,18 +311,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
303311 let this = self . eval_context_mut ( ) ;
304312
305313 let MacOsUnfairLock :: Active { mutex_ref } = this. os_unfair_lock_get_data ( lock_op) ? else {
306- // Trying to get a poisoned lock. Just block forever...
307- this. block_thread (
308- BlockReason :: Sleep ,
309- None ,
310- callback ! (
311- @capture<' tcx> { }
312- |_this, _unblock: UnblockKind | {
313- panic!( "we shouldn't wake up ever" )
314- }
315- ) ,
314+ // Trying to lock a perma-locked lock. On macOS this would block or abort depending
315+ // on whether the current thread is considered to be the one holding this lock. We
316+ // don't know who is considered to be holding the lock so we don't know what to do.
317+ throw_unsup_format ! (
318+ "attempted to lock an os_unfair_lock that was copied while being locked"
316319 ) ;
317- return interp_ok ( ( ) ) ;
318320 } ;
319321 let mutex_ref = mutex_ref. clone ( ) ;
320322
@@ -342,15 +344,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
342344 let this = self . eval_context_mut ( ) ;
343345
344346 let MacOsUnfairLock :: Active { mutex_ref } = this. os_unfair_lock_get_data ( lock_op) ? else {
345- // Trying to get a poisoned lock. That never works.
347+ // Trying to lock a perma-locked lock. That behaves the same no matter who the owner is
348+ // so we can implement the real behavior here.
346349 this. write_scalar ( Scalar :: from_bool ( false ) , dest) ?;
347350 return interp_ok ( ( ) ) ;
348351 } ;
349352 let mutex_ref = mutex_ref. clone ( ) ;
350353
351354 if mutex_ref. owner ( ) . is_some ( ) {
352- // Contrary to the blocking lock function, this does not check for
353- // reentrancy.
355+ // Contrary to the blocking lock function, this does not check for reentrancy.
354356 this. write_scalar ( Scalar :: from_bool ( false ) , dest) ?;
355357 } else {
356358 this. mutex_lock ( & mutex_ref) ?;
@@ -364,10 +366,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
364366 let this = self . eval_context_mut ( ) ;
365367
366368 let MacOsUnfairLock :: Active { mutex_ref } = this. os_unfair_lock_get_data ( lock_op) ? else {
367- // A perma-locked lock is definitely not held by us .
368- throw_machine_stop ! ( TerminationInfo :: Abort (
369- "attempted to unlock an os_unfair_lock not owned by the current thread" . to_owned ( )
370- ) ) ;
369+ // We don't know who the owner is so we cannot proceed .
370+ throw_unsup_format ! (
371+ "attempted to unlock an os_unfair_lock that was copied while being locked"
372+ ) ;
371373 } ;
372374 let mutex_ref = mutex_ref. clone ( ) ;
373375
@@ -393,10 +395,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
393395 let this = self . eval_context_mut ( ) ;
394396
395397 let MacOsUnfairLock :: Active { mutex_ref } = this. os_unfair_lock_get_data ( lock_op) ? else {
396- // A perma-locked lock is definitely not held by us .
397- throw_machine_stop ! ( TerminationInfo :: Abort (
398- "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread" . to_owned ( )
399- ) ) ;
398+ // We don't know who the owner is so we cannot proceed .
399+ throw_unsup_format ! (
400+ "attempted to assert the owner of an os_unfair_lock that was copied while being locked"
401+ ) ;
400402 } ;
401403 let mutex_ref = mutex_ref. clone ( ) ;
402404
@@ -415,8 +417,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
415417 let this = self . eval_context_mut ( ) ;
416418
417419 let MacOsUnfairLock :: Active { mutex_ref } = this. os_unfair_lock_get_data ( lock_op) ? else {
418- // A perma-locked lock is definitely not held by us.
419- return interp_ok ( ( ) ) ;
420+ // We don't know who the owner is so we cannot proceed.
421+ throw_unsup_format ! (
422+ "attempted to assert the owner of an os_unfair_lock that was copied while being locked"
423+ ) ;
420424 } ;
421425 let mutex_ref = mutex_ref. clone ( ) ;
422426
0 commit comments