@@ -22,7 +22,7 @@ use core::borrow;
2222use core:: fmt;
2323use core:: cmp:: Ordering ;
2424use core:: intrinsics:: abort;
25- use core:: mem:: { self , size_of_val, uninitialized} ;
25+ use core:: mem:: { self , align_of_val , size_of_val, uninitialized} ;
2626use core:: ops:: Deref ;
2727use core:: ops:: CoerceUnsized ;
2828use core:: ptr:: { self , Shared } ;
@@ -324,7 +324,9 @@ impl<T> Arc<T> {
324324 Ok ( elem)
325325 }
326326 }
327+ }
327328
329+ impl < T : ?Sized > Arc < T > {
328330 /// Consumes the `Arc`, returning the wrapped pointer.
329331 ///
330332 /// To avoid a memory leak the pointer must be converted back to an `Arc` using
@@ -378,16 +380,21 @@ impl<T> Arc<T> {
378380 /// ```
379381 #[ stable( feature = "rc_raw" , since = "1.17.0" ) ]
380382 pub unsafe fn from_raw ( ptr : * const T ) -> Self {
381- // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the
382- // `data` field from the pointer.
383- let ptr = ( ptr as * const u8 ) . offset ( -offset_of ! ( ArcInner <T >, data) ) ;
383+ // Align the unsized value to the end of the ArcInner.
384+ // Because it is ?Sized, it will always be the last field in memory.
385+ let align = align_of_val ( & * ptr) ;
386+ let layout = Layout :: new :: < ArcInner < ( ) > > ( ) ;
387+ let offset = ( layout. size ( ) + layout. padding_needed_for ( align) ) as isize ;
388+
389+ // Reverse the offset to find the original ArcInner.
390+ let fake_ptr = ptr as * mut ArcInner < T > ;
391+ let arc_ptr = set_data_ptr ( fake_ptr, ( ptr as * mut u8 ) . offset ( -offset) ) ;
392+
384393 Arc {
385- ptr : Shared :: new_unchecked ( ptr as * mut u8 as * mut _ ) ,
394+ ptr : Shared :: new_unchecked ( arc_ptr ) ,
386395 }
387396 }
388- }
389397
390- impl < T : ?Sized > Arc < T > {
391398 /// Creates a new [`Weak`][weak] pointer to this value.
392399 ///
393400 /// [weak]: struct.Weak.html
@@ -1491,6 +1498,28 @@ mod tests {
14911498 }
14921499 }
14931500
1501+ #[ test]
1502+ fn test_into_from_raw_unsized ( ) {
1503+ use std:: fmt:: Display ;
1504+ use std:: string:: ToString ;
1505+
1506+ let arc: Arc < str > = Arc :: from ( "foo" ) ;
1507+
1508+ let ptr = Arc :: into_raw ( arc. clone ( ) ) ;
1509+ let arc2 = unsafe { Arc :: from_raw ( ptr) } ;
1510+
1511+ assert_eq ! ( unsafe { & * ptr } , "foo" ) ;
1512+ assert_eq ! ( arc, arc2) ;
1513+
1514+ let arc: Arc < Display > = Arc :: new ( 123 ) ;
1515+
1516+ let ptr = Arc :: into_raw ( arc. clone ( ) ) ;
1517+ let arc2 = unsafe { Arc :: from_raw ( ptr) } ;
1518+
1519+ assert_eq ! ( unsafe { & * ptr } . to_string( ) , "123" ) ;
1520+ assert_eq ! ( arc2. to_string( ) , "123" ) ;
1521+ }
1522+
14941523 #[ test]
14951524 fn test_cowarc_clone_make_mut ( ) {
14961525 let mut cow0 = Arc :: new ( 75 ) ;
0 commit comments