@@ -2468,6 +2468,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Arc<T, A> {
24682468 // [2]: (https://github.com/rust-lang/rust/pull/41714)
24692469 acquire ! ( self . inner( ) . strong) ;
24702470
2471+ // Make sure we aren't trying to "drop" the shared static for empty slices
2472+ // used by Default::default.
2473+ debug_assert ! (
2474+ !ptr:: addr_eq( self . ptr. as_ptr( ) , & STATIC_INNER_SLICE . inner) ,
2475+ "Arcs backed by a static should never be reach a strong count of 0. \
2476+ Likely decrement_strong_count or from_raw were called too many times.",
2477+ ) ;
2478+
2479+
24712480 unsafe {
24722481 self . drop_slow ( ) ;
24732482 }
@@ -3059,6 +3068,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak<T, A> {
30593068
30603069 if inner. weak . fetch_sub ( 1 , Release ) == 1 {
30613070 acquire ! ( inner. weak) ;
3071+
3072+ // Make sure we aren't trying to "deallocate" the shared static for empty slices
3073+ // used by Default::default.
3074+ debug_assert ! (
3075+ !ptr:: addr_eq( self . ptr. as_ptr( ) , & STATIC_INNER_SLICE . inner) ,
3076+ "Arc/Weaks backed by a static should never be deallocated. \
3077+ Likely decrement_strong_count or from_raw were called too many times.",
3078+ ) ;
3079+
30623080 unsafe {
30633081 self . alloc . deallocate ( self . ptr . cast ( ) , Layout :: for_value_raw ( self . ptr . as_ptr ( ) ) )
30643082 }
@@ -3300,6 +3318,28 @@ impl<T: Default> Default for Arc<T> {
33003318 }
33013319}
33023320
3321+ /// Struct to hold the static `ArcInner` used for empty `Arc<str/CStr/[T]>` as
3322+ /// returned by `Default::default`.
3323+ ///
3324+ /// Layout notes:
3325+ /// * `repr(align(16))` so we can use it for `[T]` with `align_of::<T>() <= 16`.
3326+ /// * `repr(C)` so `inner` is at offset 0 (and thus guaranteed to actually be aligned to 16).
3327+ /// * `[u8; 1]` (to be initialized with 0) so it can be used for `Arc<CStr>`.
3328+ #[ repr( C , align( 16 ) ) ]
3329+ struct SliceArcInnerForStatic {
3330+ inner : ArcInner < [ u8 ; 1 ] > ,
3331+ }
3332+ const MAX_STATIC_INNER_SLICE_ALIGNMENT : usize = 16 ;
3333+
3334+ static STATIC_INNER_SLICE : SliceArcInnerForStatic = SliceArcInnerForStatic {
3335+ inner : ArcInner {
3336+ strong : atomic:: AtomicUsize :: new ( 1 ) ,
3337+ weak : atomic:: AtomicUsize :: new ( 1 ) ,
3338+ data : [ 0 ] ,
3339+ } ,
3340+ } ;
3341+
3342+
33033343#[ cfg( not( no_global_oom_handling) ) ]
33043344#[ stable( feature = "more_rc_default_impls" , since = "CURRENT_RUSTC_VERSION" ) ]
33053345impl Default for Arc < str > {
@@ -3324,12 +3364,7 @@ impl Default for Arc<core::ffi::CStr> {
33243364 #[ inline]
33253365 fn default ( ) -> Self {
33263366 use core:: ffi:: CStr ;
3327- static STATIC_INNER_CSTR : ArcInner < [ u8 ; 1 ] > = ArcInner {
3328- strong : atomic:: AtomicUsize :: new ( 1 ) ,
3329- weak : atomic:: AtomicUsize :: new ( 1 ) ,
3330- data : [ 0 ] ,
3331- } ;
3332- let inner: NonNull < ArcInner < [ u8 ] > > = NonNull :: from ( & STATIC_INNER_CSTR ) ;
3367+ let inner: NonNull < ArcInner < [ u8 ] > > = NonNull :: from ( & STATIC_INNER_SLICE . inner ) ;
33333368 let inner: NonNull < ArcInner < CStr > > = NonNull :: new ( inner. as_ptr ( ) as * mut ArcInner < CStr > ) . unwrap ( ) ;
33343369 // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
33353370 let this: mem:: ManuallyDrop < Arc < CStr > > = unsafe { mem:: ManuallyDrop :: new ( Arc :: from_inner ( inner) ) } ;
@@ -3345,31 +3380,15 @@ impl<T> Default for Arc<[T]> {
33453380 /// This may or may not share an allocation with other Arcs.
33463381 #[ inline]
33473382 fn default ( ) -> Self {
3348- let alignment_of_t: usize = mem:: align_of :: < T > ( ) ;
3349- // We only make statics for the lowest five alignments.
3350- // Alignments greater than that will use dynamic allocation.
3351- macro_rules! use_static_inner_for_alignments {
3352- ( $( $alignment: literal) ,* ) => {
3353- $( if alignment_of_t == $alignment {
3354- // Note: this must be in a new scope because static and type names are unhygenic.
3355- #[ repr( align( $alignment) ) ]
3356- struct Aligned ;
3357- static ALIGNED_STATIC_INNER : ArcInner <Aligned > = ArcInner {
3358- strong: atomic:: AtomicUsize :: new( 1 ) ,
3359- weak: atomic:: AtomicUsize :: new( 1 ) ,
3360- data: Aligned ,
3361- } ;
3362- let inner: NonNull <ArcInner <Aligned >> = NonNull :: from( & ALIGNED_STATIC_INNER ) ;
3363- let inner: NonNull <ArcInner <[ T ; 0 ] >> = inner. cast( ) ;
3364- // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
3365- let this: mem:: ManuallyDrop <Arc <[ T ; 0 ] >> = unsafe { mem:: ManuallyDrop :: new( Arc :: from_inner( inner) ) } ;
3366- return ( * this) . clone( ) ;
3367- } ) *
3368- } ;
3383+ if mem:: align_of :: < T > ( ) <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
3384+ let inner: NonNull < ArcInner < [ u8 ; 1 ] > > = NonNull :: from ( & STATIC_INNER_SLICE . inner ) ;
3385+ let inner: NonNull < ArcInner < [ T ; 0 ] > > = inner. cast ( ) ;
3386+ // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
3387+ let this: mem:: ManuallyDrop < Arc < [ T ; 0 ] > > = unsafe { mem:: ManuallyDrop :: new ( Arc :: from_inner ( inner) ) } ;
3388+ return ( * this) . clone ( ) ;
33693389 }
3370- use_static_inner_for_alignments ! ( 1 , 2 , 4 , 8 , 16 ) ;
33713390
3372- // If T's alignment is not one of the ones we have a static for , make a new unique allocation.
3391+ // If T's alignment is too large for the static, make a new unique allocation.
33733392 let arr: [ T ; 0 ] = [ ] ;
33743393 Arc :: from ( arr)
33753394 }
0 commit comments