@@ -34,6 +34,9 @@ use core::{
3434} ;
3535use macros:: pin_data;
3636
37+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
38+ use crate :: sync:: lockdep:: LockdepMap ;
39+
3740mod std_vendor;
3841
3942/// A reference-counted pointer to an instance of `T`.
@@ -130,6 +133,17 @@ pub struct Arc<T: ?Sized> {
130133 _p : PhantomData < ArcInner < T > > ,
131134}
132135
136+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
137+ #[ pin_data]
138+ #[ repr( C ) ]
139+ struct ArcInner < T : ?Sized > {
140+ refcount : Opaque < bindings:: refcount_t > ,
141+ lockdep_map : LockdepMap ,
142+ data : T ,
143+ }
144+
145+ // FIXME: pin_data does not work well with cfg attributes within the struct definition.
146+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
133147#[ pin_data]
134148#[ repr( C ) ]
135149struct ArcInner < T : ?Sized > {
@@ -192,11 +206,14 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
192206
193207impl < T > Arc < T > {
194208 /// Constructs a new reference counted instance of `T`.
209+ #[ track_caller]
195210 pub fn new ( contents : T , flags : Flags ) -> Result < Self , AllocError > {
196211 // INVARIANT: The refcount is initialised to a non-zero value.
197212 let value = ArcInner {
198213 // SAFETY: There are no safety requirements for this FFI call.
199214 refcount : Opaque :: new ( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
215+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
216+ lockdep_map : LockdepMap :: new ( ) ,
200217 data : contents,
201218 } ;
202219
@@ -390,15 +407,50 @@ impl<T: ?Sized> Drop for Arc<T> {
390407 // freed/invalid memory as long as it is never dereferenced.
391408 let refcount = unsafe { self . ptr . as_ref ( ) } . refcount . get ( ) ;
392409
410+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
411+ // SAFETY: By the type invariant, there is necessarily a reference to the object.
412+ // We cannot hold the map lock across the reference decrement, as we might race
413+ // another thread. Therefore, we lock and immediately drop the guard here. This
414+ // only serves to inform lockdep of the dependency up the call stack.
415+ unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
416+
393417 // INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
394418 // this instance is being dropped, so the broken invariant is not observable.
395419 // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
396420 let is_zero = unsafe { bindings:: refcount_dec_and_test ( refcount) } ;
421+
397422 if is_zero {
398423 // The count reached zero, we must free the memory.
399- //
400- // SAFETY: The pointer was initialised from the result of `KBox::leak`.
401- unsafe { drop ( KBox :: from_raw ( self . ptr . as_ptr ( ) ) ) } ;
424+
425+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
426+ // SAFETY: If we get this far, we had the last reference to the object.
427+ // That means we are responsible for freeing it, so we can safely lock
428+ // the fake lock again. This wraps dropping the inner object, which
429+ // informs lockdep of the dependencies down the call stack.
430+ let guard = unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
431+
432+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
433+ // and the value is valid.
434+ unsafe { core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . data ) } ;
435+
436+ // We need to drop the lock guard before freeing the LockdepMap itself
437+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
438+ core:: mem:: drop ( guard) ;
439+
440+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
441+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
442+ // and the lockdep map is valid.
443+ unsafe {
444+ core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . lockdep_map )
445+ } ;
446+
447+ // SAFETY: The pointer was initialised from the result of `Box::leak`, and
448+ // a ManuallyDrop<T> is compatible. We already dropped the contents above.
449+ unsafe {
450+ drop ( KBox :: from_raw (
451+ self . ptr . as_ptr ( ) as * mut ManuallyDrop < ArcInner < T > >
452+ ) )
453+ } ;
402454 }
403455 }
404456}
@@ -630,6 +682,7 @@ pub struct UniqueArc<T: ?Sized> {
630682
631683impl < T > UniqueArc < T > {
632684 /// Tries to allocate a new [`UniqueArc`] instance.
685+ #[ track_caller]
633686 pub fn new ( value : T , flags : Flags ) -> Result < Self , AllocError > {
634687 Ok ( Self {
635688 // INVARIANT: The newly-created object has a refcount of 1.
@@ -638,8 +691,24 @@ impl<T> UniqueArc<T> {
638691 }
639692
640693 /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
694+ #[ track_caller]
641695 pub fn new_uninit ( flags : Flags ) -> Result < UniqueArc < MaybeUninit < T > > , AllocError > {
642696 // INVARIANT: The refcount is initialised to a non-zero value.
697+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
698+ let inner = {
699+ let map = LockdepMap :: new ( ) ;
700+ KBox :: try_init :: < AllocError > (
701+ try_init ! ( ArcInner {
702+ // SAFETY: There are no safety requirements for this FFI call.
703+ refcount: Opaque :: new( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
704+ lockdep_map: map,
705+ data <- init:: uninit:: <T , AllocError >( ) ,
706+ } ? AllocError ) ,
707+ flags,
708+ ) ?
709+ } ;
710+ // FIXME: try_init!() does not work with cfg attributes.
711+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
643712 let inner = KBox :: try_init :: < AllocError > (
644713 try_init ! ( ArcInner {
645714 // SAFETY: There are no safety requirements for this FFI call.
0 commit comments