rust-lang/rust · #162102

`alloc` crate: shrink undocumented `unsafe` blocks

DanielEScherzer · merged Sep 1, 202615 files · 133 + / 125
library/alloc/src/boxed/thin.rs53 + / 45
@@ -165,10 +165,10 @@ impl<T: ?Sized> DerefMut for ThinBox<T> { #[unstable(feature = "thin_box", issue = "92791")] impl<T: ?Sized> Drop for ThinBox<T> {     fn drop(&mut self) {+        let value = self.deref_mut();+        let value = value as *mut T;         // ignore-tidy-undocumented-unsafe         unsafe {-            let value = self.deref_mut();-            let value = value as *mut T;             self.with_header().drop::<T>(value);         }     }@@ -240,34 +240,38 @@ impl<H> WithHeader<H> {             alloc::handle_alloc_error(Layout::new::<()>());         }; -        // ignore-tidy-undocumented-unsafe-        unsafe {-            // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so-            // we use `layout.dangling()` for this case, which should have a valid-            // alignment for both `T` and `H`.-            let ptr = if layout.size() == 0 {-                // Some paranoia checking, mostly so that the ThinBox tests are-                // more able to catch issues.-                debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);-                layout.dangling_ptr()-            } else {-                let ptr = alloc::alloc(layout);-                if ptr.is_null() {-                    alloc::handle_alloc_error(layout);-                }-                // Safety:-                // - The size is at least `aligned_header_size`.+        // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so+        // we use `layout.dangling()` for this case, which should have a valid+        // alignment for both `T` and `H`.+        let ptr = if layout.size() == 0 {+            // Some paranoia checking, mostly so that the ThinBox tests are+            // more able to catch issues.+            debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);+            layout.dangling_ptr()+        } else {+            // ignore-tidy-undocumented-unsafe+            let ptr = unsafe { alloc::alloc(layout) };+            if ptr.is_null() {+                alloc::handle_alloc_error(layout);+            }+            // SAFETY:+            // - The size is at least `aligned_header_size`.+            unsafe {                 let ptr = ptr.add(value_offset) as *mut _;                  NonNull::new_unchecked(ptr)-            };+            }+        }; -            let result = WithHeader(ptr, PhantomData);+        let result = WithHeader(ptr, PhantomData);++        // ignore-tidy-undocumented-unsafe+        unsafe {             ptr::write(result.header(), header);             ptr::write(result.value().cast(), value);--            result         }++        result     }      /// Non-panicking version of `new`.@@ -278,35 +282,39 @@ impl<H> WithHeader<H> {             return Err(core::alloc::AllocError);         }; -        // ignore-tidy-undocumented-unsafe-        unsafe {-            // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so-            // we use `layout.dangling()` for this case, which should have a valid-            // alignment for both `T` and `H`.-            let ptr = if layout.size() == 0 {-                // Some paranoia checking, mostly so that the ThinBox tests are-                // more able to catch issues.-                debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);-                layout.dangling_ptr()-            } else {-                let ptr = alloc::alloc(layout);-                if ptr.is_null() {-                    return Err(core::alloc::AllocError);-                }--                // Safety:-                // - The size is at least `aligned_header_size`.+        // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so+        // we use `layout.dangling()` for this case, which should have a valid+        // alignment for both `T` and `H`.+        let ptr = if layout.size() == 0 {+            // Some paranoia checking, mostly so that the ThinBox tests are+            // more able to catch issues.+            debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);+            layout.dangling_ptr()+        } else {+            // ignore-tidy-undocumented-unsafe+            let ptr = unsafe { alloc::alloc(layout) };+            if ptr.is_null() {+                return Err(core::alloc::AllocError);+            }++            // SAFETY:+            // - The size is at least `aligned_header_size`.+            unsafe {                 let ptr = ptr.add(value_offset) as *mut _;                  NonNull::new_unchecked(ptr)-            };+            }+        };++        let result = WithHeader(ptr, PhantomData); -            let result = WithHeader(ptr, PhantomData);+        // ignore-tidy-undocumented-unsafe+        unsafe {             ptr::write(result.header(), header);             ptr::write(result.value().cast(), value);--            Ok(result)         }++        Ok(result)     }      // `Dyn` is `?Sized` type like `[u32]`, and `T` is ZST type like `[u32; 0]`.
library/alloc/src/collections/binary_heap/mod.rs2 + / 2
@@ -1574,9 +1574,9 @@ impl<'a, T> Hole<'a, T> {     unsafe fn move_to(&mut self, index: usize) {         debug_assert!(index != self.pos);         debug_assert!(index < self.data.len());+        let ptr = self.data.as_mut_ptr();         // ignore-tidy-undocumented-unsafe         unsafe {-            let ptr = self.data.as_mut_ptr();             let index_ptr: *const _ = ptr.add(index);             let hole_ptr = ptr.add(self.pos);             ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);@@ -1589,9 +1589,9 @@ impl<T> Drop for Hole<'_, T> {     #[inline]     fn drop(&mut self) {         // fill the hole again+        let pos = self.pos;         // ignore-tidy-undocumented-unsafe         unsafe {-            let pos = self.pos;             ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);         }     }
library/alloc/src/collections/btree/map.rs3 + / 3
@@ -280,10 +280,10 @@ impl<K: Clone, V: Clone, A: AllocatorClone> Clone for BTreeMap<K, V, A> {                              // We can't destructure subtree directly                             // because BTreeMap implements Drop-                            // ignore-tidy-undocumented-unsafe-                            let (subroot, sublength) = unsafe {+                            let (subroot, sublength) = {                                 let subtree = ManuallyDrop::new(subtree);-                                let root = ptr::read(&subtree.root);+                                // ignore-tidy-undocumented-unsafe+                                let root = unsafe { ptr::read(&subtree.root) };                                 let length = subtree.length;                                 (root, length)                             };
library/alloc/src/collections/btree/node.rs8 + / 8
@@ -1875,11 +1875,11 @@ pub(super) mod marker { /// # Safety /// The slice has more than `idx` elements. unsafe fn slice_insert<T>(slice: &mut [MaybeUninit<T>], idx: usize, val: T) {+    let len = slice.len();+    debug_assert!(len > idx);+    let slice_ptr = slice.as_mut_ptr();     // ignore-tidy-undocumented-unsafe     unsafe {-        let len = slice.len();-        debug_assert!(len > idx);-        let slice_ptr = slice.as_mut_ptr();         if len > idx + 1 {             ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx - 1);         }@@ -1893,11 +1893,11 @@ unsafe fn slice_insert<T>(slice: &mut [MaybeUninit<T>], idx: usize, val: T) { /// # Safety /// The slice has more than `idx` elements. unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T {+    let len = slice.len();+    debug_assert!(idx < len);+    let slice_ptr = slice.as_mut_ptr();     // ignore-tidy-undocumented-unsafe     unsafe {-        let len = slice.len();-        debug_assert!(idx < len);-        let slice_ptr = slice.as_mut_ptr();         let ret = (*slice_ptr.add(idx)).assume_init_read();         ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1);         ret@@ -1909,9 +1909,9 @@ unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T { /// # Safety /// The slice has at least `distance` elements. unsafe fn slice_shl<T>(slice: &mut [MaybeUninit<T>], distance: usize) {+    let slice_ptr = slice.as_mut_ptr();     // ignore-tidy-undocumented-unsafe     unsafe {-        let slice_ptr = slice.as_mut_ptr();         ptr::copy(slice_ptr.add(distance), slice_ptr, slice.len() - distance);     } }@@ -1921,9 +1921,9 @@ unsafe fn slice_shl<T>(slice: &mut [MaybeUninit<T>], distance: usize) { /// # Safety /// The slice has at least `distance` elements. unsafe fn slice_shr<T>(slice: &mut [MaybeUninit<T>], distance: usize) {+    let slice_ptr = slice.as_mut_ptr();     // ignore-tidy-undocumented-unsafe     unsafe {-        let slice_ptr = slice.as_mut_ptr();         ptr::copy(slice_ptr, slice_ptr.add(distance), slice.len() - distance);     } }
library/alloc/src/collections/linked_list.rs28 + / 28
@@ -1679,20 +1679,20 @@ impl<'a, T> CursorMut<'a, T> {     /// inserted at the start of the `LinkedList`.     #[unstable(feature = "linked_list_cursors", issue = "58533")]     pub fn splice_after(&mut self, list: LinkedList<T>) {+        let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else {+            return;+        };         // ignore-tidy-undocumented-unsafe         unsafe {-            let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else {-                return;-            };             let node_next = match self.current {                 None => self.list.head,                 Some(node) => node.as_ref().next,             };             self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len);-            if self.current.is_none() {-                // The "ghost" non-element's index has changed.-                self.index = self.list.len;-            }+        }+        if self.current.is_none() {+            // The "ghost" non-element's index has changed.+            self.index = self.list.len;         }     } @@ -1702,19 +1702,19 @@ impl<'a, T> CursorMut<'a, T> {     /// inserted at the end of the `LinkedList`.     #[unstable(feature = "linked_list_cursors", issue = "58533")]     pub fn splice_before(&mut self, list: LinkedList<T>) {+        let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {+            Some(parts) => parts,+            _ => return,+        };         // ignore-tidy-undocumented-unsafe         unsafe {-            let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {-                Some(parts) => parts,-                _ => return,-            };             let node_prev = match self.current {                 None => self.list.tail,                 Some(node) => node.as_ref().prev,             };             self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len);-            self.index += splice_len;         }+        self.index += splice_len;     } } @@ -1725,19 +1725,19 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {     /// inserted at the front of the `LinkedList`.     #[unstable(feature = "linked_list_cursors", issue = "58533")]     pub fn insert_after(&mut self, item: T) {+        let spliced_node =+            Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0;         // ignore-tidy-undocumented-unsafe         unsafe {-            let spliced_node =-                Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0;             let node_next = match self.current {                 None => self.list.head,                 Some(node) => node.as_ref().next,             };             self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1);-            if self.current.is_none() {-                // The "ghost" non-element's index has changed.-                self.index = self.list.len;-            }+        }+        if self.current.is_none() {+            // The "ghost" non-element's index has changed.+            self.index = self.list.len;         }     } @@ -1747,17 +1747,17 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {     /// inserted at the end of the `LinkedList`.     #[unstable(feature = "linked_list_cursors", issue = "58533")]     pub fn insert_before(&mut self, item: T) {+        let spliced_node =+            Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0;         // ignore-tidy-undocumented-unsafe         unsafe {-            let spliced_node =-                Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0;             let node_prev = match self.current {                 None => self.list.tail,                 Some(node) => node.as_ref().prev,             };             self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1);-            self.index += 1;         }+        self.index += 1;     }      /// Removes the current element from the `LinkedList`.@@ -1799,14 +1799,14 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {              unlinked_node.as_mut().prev = None;             unlinked_node.as_mut().next = None;-            Some(LinkedList {-                head: Some(unlinked_node),-                tail: Some(unlinked_node),-                len: 1,-                alloc: self.list.alloc.clone(),-                marker: PhantomData,-            })         }+        Some(LinkedList {+            head: Some(unlinked_node),+            tail: Some(unlinked_node),+            len: 1,+            alloc: self.list.alloc.clone(),+            marker: PhantomData,+        })     }      /// Splits the list into two after the current element. This will return a
library/alloc/src/collections/vec_deque/mod.rs14 + / 12
@@ -1455,18 +1455,19 @@ impl<T, A: Allocator> VecDeque<T, A> {     #[doc(alias = "retain_front")]     #[stable(feature = "deque_extras", since = "1.16.0")]     pub fn truncate(&mut self, len: usize) {+        if len >= self.len {+            return;+        }++        let (front, back) = self.as_mut_slices();+         // SAFETY:         // * Any slice passed to `drop_in_place` is valid; the second case has         //   `len <= front.len()` and returning on `len > self.len()` ensures         //   `begin <= back.len()` in the first case         // * The head of the VecDeque is moved before calling `drop_in_place`,         //   so no value is dropped twice if `drop_in_place` panics         unsafe {-            if len >= self.len {-                return;-            }--            let (front, back) = self.as_mut_slices();             if len > front.len() {                 let begin = len - front.len();                 let drop_back = back.get_unchecked_mut(begin..) as *mut _;@@ -1508,14 +1509,15 @@ impl<T, A: Allocator> VecDeque<T, A> {     #[doc(alias = "truncate_front")]     #[stable(feature = "vec_deque_truncate_front", since = "1.99.0")]     pub fn retain_back(&mut self, len: usize) {+        if len >= self.len {+            // No action is taken+            return;+        }++        let (front, back) = self.as_mut_slices();+         // ignore-tidy-undocumented-unsafe         unsafe {-            if len >= self.len {-                // No action is taken-                return;-            }--            let (front, back) = self.as_mut_slices();             if len > back.len() {                 // The 'back' slice remains unchanged.                 // front.len() + back.len() == self.len, so 'end' is non-negative@@ -2773,9 +2775,9 @@ impl<T, A: Allocator> VecDeque<T, A> {         }          self.reserve(other.len);+        let (left, right) = other.as_slices();         // ignore-tidy-undocumented-unsafe         unsafe {-            let (left, right) = other.as_slices();             self.copy_slice(self.to_wrapped_index(self.len), left);             // no overflow, because self.capacity() >= old_cap + left.len() >= self.len + left.len()             self.copy_slice(self.to_wrapped_index(self.len + left.len()), right);
library/alloc/src/collections/vec_deque/spec_extend.rs2 + / 2
@@ -86,8 +86,8 @@ impl<T, A1: Allocator, A2: Allocator> SpecExtend<T, vec::IntoIter<T, A2>> for Ve         // ignore-tidy-undocumented-unsafe         unsafe {             self.copy_slice(self.to_wrapped_index(self.len), slice);-            self.len += slice.len();         }+        self.len += slice.len();         iterator.forget_remaining_elements_and_dealloc();     } }@@ -113,8 +113,8 @@ where         // ignore-tidy-undocumented-unsafe         unsafe {             self.copy_slice(self.to_wrapped_index(self.len), slice);-            self.len += slice.len();         }+        self.len += slice.len();     } } 
library/alloc/src/collections/vec_deque/splice.rs2 + / 2
@@ -64,10 +64,10 @@ impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {         // At this point draining is done and the only remaining tasks are splicing         // and moving things into the final place. +        let tail_len = self.drain.tail_len; // #elements behind the drain+         // ignore-tidy-undocumented-unsafe         unsafe {-            let tail_len = self.drain.tail_len; // #elements behind the drain-             if tail_len == 0 {                 self.drain.deque.as_mut().extend(self.replace_with.by_ref());                 return;
library/alloc/src/rc.rs1 + / 1
@@ -2395,9 +2395,9 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {      #[cfg(not(no_global_oom_handling))]     fn from_box_in(src: Box<T, A>) -> Rc<T, A> {+        let value_size = size_of_val(&*src);         // ignore-tidy-undocumented-unsafe         unsafe {-            let value_size = size_of_val(&*src);             let ptr = Self::allocate_for_ptr_in(&*src, Box::allocator(&src));              // Copy value as bytes
library/alloc/src/slice.rs3 + / 5
@@ -474,12 +474,10 @@ impl<T> [T] {     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]     #[inline]     pub const fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {+        let len = self.len();+        let (b, alloc) = Box::into_raw_with_allocator(self);         // ignore-tidy-undocumented-unsafe-        unsafe {-            let len = self.len();-            let (b, alloc) = Box::into_raw_with_allocator(self);-            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)-        }+        unsafe { Vec::from_raw_parts_in(b as *mut T, len, len, alloc) }     }      /// Creates a vector by copying a slice `n` times.
library/alloc/src/str.rs2 + / 2
@@ -181,10 +181,10 @@ where      result.extend_from_slice(first); +    let pos = result.len();+    debug_assert!(reserved_len >= pos);     // ignore-tidy-undocumented-unsafe     unsafe {-        let pos = result.len();-        debug_assert!(reserved_len >= pos);         let target = result.spare_capacity_mut().get_unchecked_mut(..reserved_len - pos);          // Convert the separator and slices to slices of MaybeUninit
library/alloc/src/sync.rs1 + / 1
@@ -860,9 +860,9 @@ impl<T, A: Allocator> Arc<T, A> {          // Now we can properly initialize the inner value and turn our weak         // reference into a strong reference.+        let inner = init_ptr.as_ptr();         // ignore-tidy-undocumented-unsafe         unsafe {-            let inner = init_ptr.as_ptr();             ptr::write(&raw mut (*inner).data, data);              // The above write to the data field must be visible to any threads which
library/alloc/src/vec/in_place_collect.rs4 + / 4
@@ -340,12 +340,12 @@ fn write_in_place_with_drop<T>(     src_end: *const T, ) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {     move |mut sink, item| {+        // the InPlaceIterable contract cannot be verified precisely here since+        // try_fold has an exclusive reference to the source pointer+        // all we can do is check if it's still in range+        debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");         // ignore-tidy-undocumented-unsafe         unsafe {-            // the InPlaceIterable contract cannot be verified precisely here since-            // try_fold has an exclusive reference to the source pointer-            // all we can do is check if it's still in range-            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");             ptr::write(sink.dst, item);             // Since this executes user code which can panic we have to bump the pointer             // after each step.
library/alloc/src/vec/mod.rs9 + / 9
@@ -1733,10 +1733,10 @@ impl<T, A: Allocator> Vec<T, A> {     #[cfg(not(no_global_oom_handling))]     #[stable(feature = "rust1", since = "1.0.0")]     pub fn into_boxed_slice(mut self) -> Box<[T], A> {+        self.shrink_to_fit();+        let me = ManuallyDrop::new(self);         // ignore-tidy-undocumented-unsafe         unsafe {-            self.shrink_to_fit();-            let me = ManuallyDrop::new(self);             let buf = ptr::read(&me.buf);             let len = me.len();             buf.into_box(len).assume_init()@@ -2449,10 +2449,10 @@ impl<T, A: Allocator> Vec<T, A> {         if index >= len {             return None;         }+        // infallible+        let ret;         // ignore-tidy-undocumented-unsafe         unsafe {-            // infallible-            let ret;             {                 // the place we are taking from.                 let ptr = self.as_mut_ptr().add(index);@@ -2464,8 +2464,8 @@ impl<T, A: Allocator> Vec<T, A> {                 ptr::copy(ptr.add(1), ptr, len - index - 1);             }             self.set_len(len - 1);-            Some(ret)         }+        Some(ret)     }      /// Retains only the elements specified by the predicate.@@ -2906,9 +2906,9 @@ impl<T, A: Allocator> Vec<T, A> {         if self.len == 0 {             None         } else {+            self.len -= 1;             // ignore-tidy-undocumented-unsafe             unsafe {-                self.len -= 1;                 core::hint::assert_unchecked(self.len < self.capacity());                 Some(ptr::read(self.as_ptr().add(self.len())))             }@@ -4067,9 +4067,9 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {     /// ```     #[inline]     fn into_iter(self) -> Self::IntoIter {+        let me = ManuallyDrop::new(self);         // ignore-tidy-undocumented-unsafe         unsafe {-            let me = ManuallyDrop::new(self);             let alloc = ManuallyDrop::new(ptr::read(me.allocator()));             let buf = me.buf.non_null();             let begin = buf.as_ptr();@@ -4175,10 +4175,10 @@ impl<T, A: Allocator> Vec<T, A> {                 (low, high)             );             self.reserve(additional);+            let ptr = self.as_mut_ptr();+            let mut local_len = SetLenOnDrop::new(&mut self.len);             // ignore-tidy-undocumented-unsafe             unsafe {-                let ptr = self.as_mut_ptr();-                let mut local_len = SetLenOnDrop::new(&mut self.len);                 iterator.for_each(move |element| {                     ptr::write(ptr.add(local_len.current_len()), element);                     // Since the loop executes user code which can panic we have to update
library/alloc/src/vec/spec_from_iter.rs1 + / 1
@@ -46,9 +46,9 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {         // But it is a conservative choice.         let has_advanced = iterator.buf != iterator.ptr;         if !has_advanced || iterator.len() >= iterator.cap / 2 {+            let it = ManuallyDrop::new(iterator);             // ignore-tidy-undocumented-unsafe             unsafe {-                let it = ManuallyDrop::new(iterator);                 if has_advanced {                     ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len());                 }