@@ -2150,7 +2150,8 @@ unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
2150
2150
#[ unstable( feature = "receiver_trait" , issue = "none" ) ]
2151
2151
impl < T : ?Sized > Receiver for Arc < T > { }
2152
2152
2153
- impl < T : Clone , A : Allocator + Clone > Arc < T , A > {
2153
+ #[ cfg( not( no_global_oom_handling) ) ]
2154
+ impl < T : ?Sized + CloneToUninit , A : Allocator + Clone > Arc < T , A > {
2154
2155
/// Makes a mutable reference into the given `Arc`.
2155
2156
///
2156
2157
/// If there are other `Arc` pointers to the same allocation, then `make_mut` will
@@ -2201,10 +2202,11 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> {
2201
2202
/// assert!(76 == *data);
2202
2203
/// assert!(weak.upgrade().is_none());
2203
2204
/// ```
2204
- #[ cfg( not( no_global_oom_handling) ) ]
2205
2205
#[ inline]
2206
2206
#[ stable( feature = "arc_unique" , since = "1.4.0" ) ]
2207
2207
pub fn make_mut ( this : & mut Self ) -> & mut T {
2208
+ let size_of_val = mem:: size_of_val :: < T > ( & * * this) ;
2209
+
2208
2210
// Note that we hold both a strong reference and a weak reference.
2209
2211
// Thus, releasing our strong reference only will not, by itself, cause
2210
2212
// the memory to be deallocated.
@@ -2215,13 +2217,19 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> {
2215
2217
// deallocated.
2216
2218
if this. inner ( ) . strong . compare_exchange ( 1 , 0 , Acquire , Relaxed ) . is_err ( ) {
2217
2219
// Another strong pointer exists, so we must clone.
2218
- // Pre-allocate memory to allow writing the cloned value directly.
2219
- let mut arc = Self :: new_uninit_in ( this. alloc . clone ( ) ) ;
2220
- unsafe {
2221
- let data = Arc :: get_mut_unchecked ( & mut arc) ;
2222
- ( * * this) . clone_to_uninit ( data. as_mut_ptr ( ) ) ;
2223
- * this = arc. assume_init ( ) ;
2224
- }
2220
+
2221
+ let this_data_ref: & T = & * * this;
2222
+ // `in_progress` drops the allocation if we panic before finishing initializing it.
2223
+ let mut in_progress: UniqueArcUninit < T , A > =
2224
+ UniqueArcUninit :: new ( this_data_ref, this. alloc . clone ( ) ) ;
2225
+
2226
+ let initialized_clone = unsafe {
2227
+ // Clone. If the clone panics, `in_progress` will be dropped and clean up.
2228
+ this_data_ref. clone_to_uninit ( in_progress. data_ptr ( ) ) ;
2229
+ // Cast type of pointer, now that it is initialized.
2230
+ in_progress. into_arc ( )
2231
+ } ;
2232
+ * this = initialized_clone;
2225
2233
} else if this. inner ( ) . weak . load ( Relaxed ) != 1 {
2226
2234
// Relaxed suffices in the above because this is fundamentally an
2227
2235
// optimization: we are always racing with weak pointers being
@@ -2240,11 +2248,22 @@ impl<T: Clone, A: Allocator + Clone> Arc<T, A> {
2240
2248
let _weak = Weak { ptr : this. ptr , alloc : this. alloc . clone ( ) } ;
2241
2249
2242
2250
// Can just steal the data, all that's left is Weaks
2243
- let mut arc = Self :: new_uninit_in ( this. alloc . clone ( ) ) ;
2251
+ //
2252
+ // We don't need panic-protection like the above branch does, but we might as well
2253
+ // use the same mechanism.
2254
+ let mut in_progress: UniqueArcUninit < T , A > =
2255
+ UniqueArcUninit :: new ( & * * this, this. alloc . clone ( ) ) ;
2244
2256
unsafe {
2245
- let data = Arc :: get_mut_unchecked ( & mut arc) ;
2246
- data. as_mut_ptr ( ) . copy_from_nonoverlapping ( & * * this, 1 ) ;
2247
- ptr:: write ( this, arc. assume_init ( ) ) ;
2257
+ // Initialize `in_progress` with move of **this.
2258
+ // We have to express this in terms of bytes because `T: ?Sized`; there is no
2259
+ // operation that just copies a value based on its `size_of_val()`.
2260
+ ptr:: copy_nonoverlapping (
2261
+ ptr:: from_ref ( & * * this) . cast :: < u8 > ( ) ,
2262
+ in_progress. data_ptr ( ) . cast :: < u8 > ( ) ,
2263
+ size_of_val,
2264
+ ) ;
2265
+
2266
+ ptr:: write ( this, in_progress. into_arc ( ) ) ;
2248
2267
}
2249
2268
} else {
2250
2269
// We were the sole reference of either kind; bump back up the
@@ -3809,6 +3828,68 @@ fn data_offset_align(align: usize) -> usize {
3809
3828
layout. size ( ) + layout. padding_needed_for ( align)
3810
3829
}
3811
3830
3831
+ /// A unique owning pointer to a [`ArcInner`] **that does not imply the contents are initialized,**
3832
+ /// but will deallocate it (without dropping the value) when dropped.
3833
+ ///
3834
+ /// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic.
3835
+ #[ cfg( not( no_global_oom_handling) ) ]
3836
+ struct UniqueArcUninit < T : ?Sized , A : Allocator > {
3837
+ ptr : NonNull < ArcInner < T > > ,
3838
+ layout_for_value : Layout ,
3839
+ alloc : Option < A > ,
3840
+ }
3841
+
3842
+ #[ cfg( not( no_global_oom_handling) ) ]
3843
+ impl < T : ?Sized , A : Allocator > UniqueArcUninit < T , A > {
3844
+ /// Allocate a ArcInner with layout suitable to contain `for_value` or a clone of it.
3845
+ fn new ( for_value : & T , alloc : A ) -> UniqueArcUninit < T , A > {
3846
+ let layout = Layout :: for_value ( for_value) ;
3847
+ let ptr = unsafe {
3848
+ Arc :: allocate_for_layout (
3849
+ layout,
3850
+ |layout_for_arcinner| alloc. allocate ( layout_for_arcinner) ,
3851
+ |mem| mem. with_metadata_of ( ptr:: from_ref ( for_value) as * const ArcInner < T > ) ,
3852
+ )
3853
+ } ;
3854
+ Self { ptr : NonNull :: new ( ptr) . unwrap ( ) , layout_for_value : layout, alloc : Some ( alloc) }
3855
+ }
3856
+
3857
+ /// Returns the pointer to be written into to initialize the [`Arc`].
3858
+ fn data_ptr ( & mut self ) -> * mut T {
3859
+ let offset = data_offset_align ( self . layout_for_value . align ( ) ) ;
3860
+ unsafe { self . ptr . as_ptr ( ) . byte_add ( offset) as * mut T }
3861
+ }
3862
+
3863
+ /// Upgrade this into a normal [`Arc`].
3864
+ ///
3865
+ /// # Safety
3866
+ ///
3867
+ /// The data must have been initialized (by writing to [`Self::data_ptr()`]).
3868
+ unsafe fn into_arc ( mut self ) -> Arc < T , A > {
3869
+ let ptr = self . ptr ;
3870
+ let alloc = self . alloc . take ( ) . unwrap ( ) ;
3871
+ mem:: forget ( self ) ;
3872
+ // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible
3873
+ // for having initialized the data.
3874
+ unsafe { Arc :: from_ptr_in ( ptr. as_ptr ( ) , alloc) }
3875
+ }
3876
+ }
3877
+
3878
+ #[ cfg( not( no_global_oom_handling) ) ]
3879
+ impl < T : ?Sized , A : Allocator > Drop for UniqueArcUninit < T , A > {
3880
+ fn drop ( & mut self ) {
3881
+ // SAFETY:
3882
+ // * new() produced a pointer safe to deallocate.
3883
+ // * We own the pointer unless into_arc() was called, which forgets us.
3884
+ unsafe {
3885
+ self . alloc . take ( ) . unwrap ( ) . deallocate (
3886
+ self . ptr . cast ( ) ,
3887
+ arcinner_layout_for_value_layout ( self . layout_for_value ) ,
3888
+ ) ;
3889
+ }
3890
+ }
3891
+ }
3892
+
3812
3893
#[ stable( feature = "arc_error" , since = "1.52.0" ) ]
3813
3894
impl < T : core:: error:: Error + ?Sized > core:: error:: Error for Arc < T > {
3814
3895
#[ allow( deprecated, deprecated_in_future) ]
0 commit comments