@@ -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`.
@@ -140,6 +143,17 @@ pub struct Arc<T: ?Sized> {
140143 _p : PhantomData < ArcInner < T > > ,
141144}
142145
146+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
147+ #[ pin_data]
148+ #[ repr( C ) ]
149+ struct ArcInner < T : ?Sized > {
150+ refcount : Opaque < bindings:: refcount_t > ,
151+ lockdep_map : LockdepMap ,
152+ data : T ,
153+ }
154+
155+ // FIXME: pin_data does not work well with cfg attributes within the struct definition.
156+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
143157#[ pin_data]
144158#[ repr( C ) ]
145159struct ArcInner < T : ?Sized > {
@@ -204,11 +218,14 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
204218
205219impl < T > Arc < T > {
206220 /// Constructs a new reference counted instance of `T`.
221+ #[ track_caller]
207222 pub fn new ( contents : T , flags : Flags ) -> Result < Self , AllocError > {
208223 // INVARIANT: The refcount is initialised to a non-zero value.
209224 let value = ArcInner {
210225 // SAFETY: There are no safety requirements for this FFI call.
211226 refcount : Opaque :: new ( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
227+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
228+ lockdep_map : LockdepMap :: new ( ) ,
212229 data : contents,
213230 } ;
214231
@@ -418,15 +435,50 @@ impl<T: ?Sized> Drop for Arc<T> {
418435 // freed/invalid memory as long as it is never dereferenced.
419436 let refcount = unsafe { self . ptr . as_ref ( ) } . refcount . get ( ) ;
420437
438+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
439+ // SAFETY: By the type invariant, there is necessarily a reference to the object.
440+ // We cannot hold the map lock across the reference decrement, as we might race
441+ // another thread. Therefore, we lock and immediately drop the guard here. This
442+ // only serves to inform lockdep of the dependency up the call stack.
443+ unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
444+
421445 // INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
422446 // this instance is being dropped, so the broken invariant is not observable.
423447 // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
424448 let is_zero = unsafe { bindings:: refcount_dec_and_test ( refcount) } ;
449+
425450 if is_zero {
426451 // The count reached zero, we must free the memory.
427- //
428- // SAFETY: The pointer was initialised from the result of `KBox::leak`.
429- unsafe { drop ( KBox :: from_raw ( self . ptr . as_ptr ( ) ) ) } ;
452+
453+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
454+ // SAFETY: If we get this far, we had the last reference to the object.
455+ // That means we are responsible for freeing it, so we can safely lock
456+ // the fake lock again. This wraps dropping the inner object, which
457+ // informs lockdep of the dependencies down the call stack.
458+ let guard = unsafe { self . ptr . as_ref ( ) } . lockdep_map . lock ( ) ;
459+
460+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
461+ // and the value is valid.
462+ unsafe { core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . data ) } ;
463+
464+ // We need to drop the lock guard before freeing the LockdepMap itself
465+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
466+ core:: mem:: drop ( guard) ;
467+
468+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
469+ // SAFETY: The pointer was initialised from the result of `Box::leak`,
470+ // and the lockdep map is valid.
471+ unsafe {
472+ core:: ptr:: drop_in_place ( & mut self . ptr . as_mut ( ) . lockdep_map )
473+ } ;
474+
475+ // SAFETY: The pointer was initialised from the result of `Box::leak`, and
476+ // a ManuallyDrop<T> is compatible. We already dropped the contents above.
477+ unsafe {
478+ drop ( KBox :: from_raw (
479+ self . ptr . as_ptr ( ) as * mut ManuallyDrop < ArcInner < T > >
480+ ) )
481+ } ;
430482 }
431483 }
432484}
@@ -661,6 +713,7 @@ pub struct UniqueArc<T: ?Sized> {
661713
662714impl < T > UniqueArc < T > {
663715 /// Tries to allocate a new [`UniqueArc`] instance.
716+ #[ track_caller]
664717 pub fn new ( value : T , flags : Flags ) -> Result < Self , AllocError > {
665718 Ok ( Self {
666719 // INVARIANT: The newly-created object has a refcount of 1.
@@ -669,8 +722,24 @@ impl<T> UniqueArc<T> {
669722 }
670723
671724 /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
725+ #[ track_caller]
672726 pub fn new_uninit ( flags : Flags ) -> Result < UniqueArc < MaybeUninit < T > > , AllocError > {
673727 // INVARIANT: The refcount is initialised to a non-zero value.
728+ #[ cfg( CONFIG_RUST_EXTRA_LOCKDEP ) ]
729+ let inner = {
730+ let map = LockdepMap :: new ( ) ;
731+ KBox :: try_init :: < AllocError > (
732+ try_init ! ( ArcInner {
733+ // SAFETY: There are no safety requirements for this FFI call.
734+ refcount: Opaque :: new( unsafe { bindings:: REFCOUNT_INIT ( 1 ) } ) ,
735+ lockdep_map: map,
736+ data <- init:: uninit:: <T , AllocError >( ) ,
737+ } ? AllocError ) ,
738+ flags,
739+ ) ?
740+ } ;
741+ // FIXME: try_init!() does not work with cfg attributes.
742+ #[ cfg( not( CONFIG_RUST_EXTRA_LOCKDEP ) ) ]
674743 let inner = KBox :: try_init :: < AllocError > (
675744 try_init ! ( ArcInner {
676745 // SAFETY: There are no safety requirements for this FFI call.
0 commit comments