From 99b97737fea30228eea35214029d4e454b5d6e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 8 May 2019 17:54:25 +0000 Subject: [PATCH] style: Don't panic when creating empty ThinArcs. The change from [T; 1] to [T; 0] shouldn't change behavior since they have the right alignment and we never poke at that particular array, but feels more correct to avoid creating types that point to uninitialized data or outside of their allocation, now that we allow empty slices. Differential Revision: https://phabricator.services.mozilla.com/D30352 --- components/servo_arc/lib.rs | 48 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/components/servo_arc/lib.rs b/components/servo_arc/lib.rs index 780f7485eb9..3cc2b0e7fcc 100644 --- a/components/servo_arc/lib.rs +++ b/components/servo_arc/lib.rs @@ -168,7 +168,7 @@ impl Arc { pub fn new(data: T) -> Self { let x = Box::new(ArcInner { count: atomic::AtomicUsize::new(1), - data: data, + data, }); unsafe { Arc { @@ -610,7 +610,7 @@ impl Arc> { let size = { // First, determine the alignment of a hypothetical pointer to a // HeaderSlice. - let fake_slice_ptr_align: usize = mem::align_of::>>(); + let fake_slice_ptr_align: usize = mem::align_of::>>(); // Next, synthesize a totally garbage (but properly aligned) pointer // to a sequence of T. @@ -667,23 +667,24 @@ impl Arc> { }; ptr::write(&mut ((*ptr).count), count); ptr::write(&mut ((*ptr).data.header), header); - let mut current: *mut T = &mut (*ptr).data.slice[0]; - for _ in 0..num_items { - ptr::write( - current, - items - .next() - .expect("ExactSizeIterator over-reported length"), - ); - current = current.offset(1); + if num_items != 0 { + let mut current: *mut T = &mut (*ptr).data.slice[0]; + for _ in 0..num_items { + ptr::write( + current, + items + .next() + .expect("ExactSizeIterator over-reported length"), + ); + current = current.offset(1); + } + // We should have consumed the buffer exactly. + debug_assert_eq!(current as *mut u8, buffer.offset(size as isize)); } assert!( items.next().is_none(), "ExactSizeIterator under-reported length" ); - - // We should have consumed the buffer exactly. - debug_assert_eq!(current as *mut u8, buffer.offset(size as isize)); } // Return the fat Arc. @@ -772,11 +773,13 @@ type HeaderSliceWithLength = HeaderSlice, T>; /// have a thin pointer instead, perhaps for FFI compatibility /// or space efficiency. /// +/// Note that we use `[T; 0]` in order to have the right alignment for `T`. +/// /// `ThinArc` solves this by storing the length in the allocation itself, /// via `HeaderSliceWithLength`. #[repr(C)] pub struct ThinArc { - ptr: ptr::NonNull>>, + ptr: ptr::NonNull>>, phantom: PhantomData<(H, T)>, } @@ -787,7 +790,7 @@ unsafe impl Sync for ThinArc {} // // See the comment around the analogous operation in from_header_and_iter. fn thin_to_thick( - thin: *mut ArcInner>, + thin: *mut ArcInner>, ) -> *mut ArcInner> { let len = unsafe { (*thin).data.header.length }; let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) }; @@ -905,7 +908,7 @@ impl Arc> { let thin_ptr = fat_ptr as *mut [usize] as *mut usize; ThinArc { ptr: unsafe { - ptr::NonNull::new_unchecked(thin_ptr as *mut ArcInner>) + ptr::NonNull::new_unchecked(thin_ptr as *mut ArcInner>) }, phantom: PhantomData, } @@ -1320,6 +1323,17 @@ mod tests { } } + #[test] + fn empty_thin() { + let header = HeaderWithLength::new(100u32, 0); + let x = Arc::from_header_and_iter(header, std::iter::empty::()); + let y = Arc::into_thin(x.clone()); + assert_eq!(y.header.header, 100); + assert!(y.slice.is_empty()); + assert_eq!(x.header.header, 100); + assert!(x.slice.is_empty()); + } + #[test] fn slices_and_thin() { let mut canary = atomic::AtomicUsize::new(0);