Skip to content

Commit 6727130

Browse files
authored
Rollup merge of rust-lang#125283 - zachs18:arc-default-shared, r=dtolnay
Use a single static for all default slice Arcs. Also adds debug_asserts in Drop for Weak/Arc that the shared static is not being "dropped"/"deallocated". As per rust-lang#124640 (review) r? dtolnay
2 parents ae94e59 + 06f98cb commit 6727130

File tree

1 file changed

+56
-31
lines changed

1 file changed

+56
-31
lines changed

Diff for: alloc/src/sync.rs

+56-31
Original file line numberDiff line numberDiff line change
@@ -2496,6 +2496,14 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Arc<T, A> {
24962496
// [2]: (https://github.com/rust-lang/rust/pull/41714)
24972497
acquire!(self.inner().strong);
24982498

2499+
// Make sure we aren't trying to "drop" the shared static for empty slices
2500+
// used by Default::default.
2501+
debug_assert!(
2502+
!ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
2503+
"Arcs backed by a static should never reach a strong count of 0. \
2504+
Likely decrement_strong_count or from_raw were called too many times.",
2505+
);
2506+
24992507
unsafe {
25002508
self.drop_slow();
25012509
}
@@ -3126,6 +3134,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak<T, A> {
31263134

31273135
if inner.weak.fetch_sub(1, Release) == 1 {
31283136
acquire!(inner.weak);
3137+
3138+
// Make sure we aren't trying to "deallocate" the shared static for empty slices
3139+
// used by Default::default.
3140+
debug_assert!(
3141+
!ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
3142+
"Arc/Weaks backed by a static should never be deallocated. \
3143+
Likely decrement_strong_count or from_raw were called too many times.",
3144+
);
3145+
31293146
unsafe {
31303147
self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()))
31313148
}
@@ -3367,6 +3384,28 @@ impl<T: Default> Default for Arc<T> {
33673384
}
33683385
}
33693386

3387+
/// Struct to hold the static `ArcInner` used for empty `Arc<str/CStr/[T]>` as
3388+
/// returned by `Default::default`.
3389+
///
3390+
/// Layout notes:
3391+
/// * `repr(align(16))` so we can use it for `[T]` with `align_of::<T>() <= 16`.
3392+
/// * `repr(C)` so `inner` is at offset 0 (and thus guaranteed to actually be aligned to 16).
3393+
/// * `[u8; 1]` (to be initialized with 0) so it can be used for `Arc<CStr>`.
3394+
#[repr(C, align(16))]
3395+
struct SliceArcInnerForStatic {
3396+
inner: ArcInner<[u8; 1]>,
3397+
}
3398+
#[cfg(not(no_global_oom_handling))]
3399+
const MAX_STATIC_INNER_SLICE_ALIGNMENT: usize = 16;
3400+
3401+
static STATIC_INNER_SLICE: SliceArcInnerForStatic = SliceArcInnerForStatic {
3402+
inner: ArcInner {
3403+
strong: atomic::AtomicUsize::new(1),
3404+
weak: atomic::AtomicUsize::new(1),
3405+
data: [0],
3406+
},
3407+
};
3408+
33703409
#[cfg(not(no_global_oom_handling))]
33713410
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
33723411
impl Default for Arc<str> {
@@ -3391,15 +3430,12 @@ impl Default for Arc<core::ffi::CStr> {
33913430
#[inline]
33923431
fn default() -> Self {
33933432
use core::ffi::CStr;
3394-
static STATIC_INNER_CSTR: ArcInner<[u8; 1]> = ArcInner {
3395-
strong: atomic::AtomicUsize::new(1),
3396-
weak: atomic::AtomicUsize::new(1),
3397-
data: [0],
3398-
};
3399-
let inner: NonNull<ArcInner<[u8]>> = NonNull::from(&STATIC_INNER_CSTR);
3400-
let inner: NonNull<ArcInner<CStr>> = NonNull::new(inner.as_ptr() as *mut ArcInner<CStr>).unwrap();
3433+
let inner: NonNull<ArcInner<[u8]>> = NonNull::from(&STATIC_INNER_SLICE.inner);
3434+
let inner: NonNull<ArcInner<CStr>> =
3435+
NonNull::new(inner.as_ptr() as *mut ArcInner<CStr>).unwrap();
34013436
// `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
3402-
let this: mem::ManuallyDrop<Arc<CStr>> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
3437+
let this: mem::ManuallyDrop<Arc<CStr>> =
3438+
unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
34033439
(*this).clone()
34043440
}
34053441
}
@@ -3412,31 +3448,20 @@ impl<T> Default for Arc<[T]> {
34123448
/// This may or may not share an allocation with other Arcs.
34133449
#[inline]
34143450
fn default() -> Self {
3415-
let alignment_of_t: usize = mem::align_of::<T>();
3416-
// We only make statics for the lowest five alignments.
3417-
// Alignments greater than that will use dynamic allocation.
3418-
macro_rules! use_static_inner_for_alignments {
3419-
($($alignment:literal),*) => {
3420-
$(if alignment_of_t == $alignment {
3421-
// Note: this must be in a new scope because static and type names are unhygenic.
3422-
#[repr(align($alignment))]
3423-
struct Aligned;
3424-
static ALIGNED_STATIC_INNER: ArcInner<Aligned> = ArcInner {
3425-
strong: atomic::AtomicUsize::new(1),
3426-
weak: atomic::AtomicUsize::new(1),
3427-
data: Aligned,
3428-
};
3429-
let inner: NonNull<ArcInner<Aligned>> = NonNull::from(&ALIGNED_STATIC_INNER);
3430-
let inner: NonNull<ArcInner<[T; 0]>> = inner.cast();
3431-
// `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
3432-
let this: mem::ManuallyDrop<Arc<[T; 0]>> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
3433-
return (*this).clone();
3434-
})*
3435-
};
3451+
if mem::align_of::<T>() <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
3452+
// We take a reference to the whole struct instead of the ArcInner<[u8; 1]> inside it so
3453+
// we don't shrink the range of bytes the ptr is allowed to access under Stacked Borrows.
3454+
// (Miri complains on 32-bit targets with Arc<[Align16]> otherwise.)
3455+
// (Note that NonNull::from(&STATIC_INNER_SLICE.inner) is fine under Tree Borrows.)
3456+
let inner: NonNull<SliceArcInnerForStatic> = NonNull::from(&STATIC_INNER_SLICE);
3457+
let inner: NonNull<ArcInner<[T; 0]>> = inner.cast();
3458+
// `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
3459+
let this: mem::ManuallyDrop<Arc<[T; 0]>> =
3460+
unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
3461+
return (*this).clone();
34363462
}
3437-
use_static_inner_for_alignments!(1, 2, 4, 8, 16);
34383463

3439-
// If T's alignment is not one of the ones we have a static for, make a new unique allocation.
3464+
// If T's alignment is too large for the static, make a new unique allocation.
34403465
let arr: [T; 0] = [];
34413466
Arc::from(arr)
34423467
}

0 commit comments

Comments
 (0)