about summary refs log tree commit diff
path: root/library/alloc/src/vec
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2021-03-04 20:01:06 +0900
committerGitHub <noreply@github.com>2021-03-04 20:01:06 +0900
commit290117f7d99157e928c82d0e84effb0e9fdc409d (patch)
tree0ab49014485cb2a1511b42ac12d0671abd942318 /library/alloc/src/vec
parent569f0330d8e88aca3fabdfcb9b2dded9177002ce (diff)
parent950f12119ef724156a9a4e17e1b375eb28c6af11 (diff)
downloadrust-290117f7d99157e928c82d0e84effb0e9fdc409d.tar.gz
rust-290117f7d99157e928c82d0e84effb0e9fdc409d.zip
Rollup merge of #82564 - WaffleLapkin:revert_spare_mut, r=RalfJung
Revert `Vec::spare_capacity_mut` impl to prevent pointers invalidation

The implementation was changed in #79015.

Later it was [pointed out](https://github.com/rust-lang/rust/issues/81944#issuecomment-782849785) that the implementation invalidates pointers to the buffer (initialized elements) by creating a unique reference to the buffer. This PR reverts the implementation.

r? ```@RalfJung```
Diffstat (limited to 'library/alloc/src/vec')
-rw-r--r--library/alloc/src/vec/mod.rs24
1 files changed, 14 insertions, 10 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 01a3f9f9b59..0028e290fac 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1877,7 +1877,15 @@ impl<T, A: Allocator> Vec<T, A> {
     #[unstable(feature = "vec_spare_capacity", issue = "75017")]
     #[inline]
     pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
-        self.split_at_spare_mut().1
+        // Note:
+        // This method is not implemented in terms of `split_at_spare_mut`,
+        // to prevent invalidation of pointers to the buffer.
+        unsafe {
+            slice::from_raw_parts_mut(
+                self.as_mut_ptr().add(self.len) as *mut MaybeUninit<T>,
+                self.buf.capacity() - self.len,
+            )
+        }
     }
 
     /// Returns vector content as a slice of `T`, along with the remaining spare
@@ -1934,20 +1942,16 @@ impl<T, A: Allocator> Vec<T, A> {
     #[unstable(feature = "vec_split_at_spare", issue = "81944")]
     #[inline]
     pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [MaybeUninit<T>]) {
-        let ptr = self.as_mut_ptr();
-
-        // SAFETY:
-        // - `ptr` is guaranteed to be in bounds for `capacity` elements
-        // - `len` is guaranteed to less or equal to `capacity`
-        // - `MaybeUninit<T>` has the same layout as `T`
-        let spare_ptr = unsafe { ptr.cast::<MaybeUninit<T>>().add(self.len) };
+        let Range { start: ptr, end: spare_ptr } = self.as_mut_ptr_range();
+        let spare_ptr = spare_ptr.cast::<MaybeUninit<T>>();
+        let spare_len = self.buf.capacity() - self.len;
 
         // SAFETY:
         // - `ptr` is guaranteed to be valid for `len` elements
-        // - `spare_ptr` is offseted from `ptr` by `len`, so it doesn't overlap `initialized` slice
+        // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized`
         unsafe {
             let initialized = slice::from_raw_parts_mut(ptr, self.len);
-            let spare = slice::from_raw_parts_mut(spare_ptr, self.buf.capacity() - self.len);
+            let spare = slice::from_raw_parts_mut(spare_ptr, spare_len);
 
             (initialized, spare)
         }