From e3e6bc647d4f7fc6218c88cccd0382dc9aae50c3 Mon Sep 17 00:00:00 2001 From: Max Siling Date: Thu, 22 May 2025 19:22:13 +0300 Subject: [PATCH 1/2] assert_unsafe_precondition!(length <= capacity) in Vec::from_raw_parts This hopefully helps to catch cases where these arguments are accidentally swapped. --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index abda5aefab645..f5209c5815f3c 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -156,6 +156,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 59879f23d7850..6ecebbcb6091c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -944,6 +944,14 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + assert_unsafe_precondition!( + check_library_ub, + "Vec::from_raw_parts requires that length is less than or equal to capacity", + ( + length: usize = length, + capacity: usize = capacity, + ) => length <= capacity, + ); unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } From efdd43d4b4cd74f46c24786aa59e61f176994907 Mon Sep 17 00:00:00 2001 From: Max Siling Date: Thu, 22 May 2025 22:39:12 +0300 Subject: [PATCH 2/2] Make into_parts methods on Vec associated functions This is more consistent with `Box::into_raw()` and clears out potential confusion about whether the method acts on a vector or on a slice. --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/rc.rs | 2 +- library/alloc/src/string.rs | 6 ++-- library/alloc/src/sync.rs | 2 +- library/alloc/src/vec/mod.rs | 28 +++++++++---------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 08b1828ff000e..976d62b13433a 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -3140,7 +3140,7 @@ impl From> for VecDeque { /// any additional memory. #[inline] fn from(other: Vec) -> Self { - let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc(); + let (ptr, len, cap, alloc) = Vec::into_raw_parts_with_alloc(other); Self { head: 0, len, buf: unsafe { RawVec::from_raw_parts_in(ptr, cap, alloc) } } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4b8ea708e7e57..8f212e48f7335 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2811,7 +2811,7 @@ impl From> for Rc<[T], A> { #[inline] fn from(v: Vec) -> Rc<[T], A> { unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + let (vec_ptr, len, cap, alloc) = Vec::into_raw_parts_with_alloc(v); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 37614a7ca4571..377f2b0b42cbd 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -935,15 +935,15 @@ impl String { /// #![feature(vec_into_raw_parts)] /// let s = String::from("hello"); /// - /// let (ptr, len, cap) = s.into_raw_parts(); + /// let (ptr, len, cap) = String::into_raw_parts(s); /// /// let rebuilt = unsafe { String::from_raw_parts(ptr, len, cap) }; /// assert_eq!(rebuilt, "hello"); /// ``` #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts(self) -> (*mut u8, usize, usize) { - self.vec.into_raw_parts() + pub fn into_raw_parts(string: Self) -> (*mut u8, usize, usize) { + Vec::into_raw_parts(string.vec) } /// Creates a new `String` from a pointer, a length and a capacity. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 17090925cfa0c..90750060303fa 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3837,7 +3837,7 @@ impl From> for Arc<[T], A> { #[inline] fn from(v: Vec) -> Arc<[T], A> { unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + let (vec_ptr, len, cap, alloc) = Vec::into_raw_parts_with_alloc(v); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6ecebbcb6091c..7e6eefcc68ed6 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,4 +1,4 @@ -//! A contiguous growable array type with heap-allocated contents, written +//! A contiguous growable array type with heap-allocated contents, writtenalloc/vec/ //! `Vec`. //! //! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and @@ -1092,7 +1092,7 @@ impl Vec { /// #![feature(vec_into_raw_parts)] /// let v: Vec = vec![-1, 0, 1]; /// - /// let (ptr, len, cap) = v.into_raw_parts(); + /// let (ptr, len, cap) = Vec::into_raw_parts(v); /// /// let rebuilt = unsafe { /// // We can now make changes to the components, such as @@ -1105,8 +1105,8 @@ impl Vec { /// ``` #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts(self) -> (*mut T, usize, usize) { - let mut me = ManuallyDrop::new(self); + pub fn into_raw_parts(vec: Self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(vec); (me.as_mut_ptr(), me.len(), me.capacity()) } @@ -1133,7 +1133,7 @@ impl Vec { /// /// let v: Vec = vec![-1, 0, 1]; /// - /// let (ptr, len, cap) = v.into_parts(); + /// let (ptr, len, cap) = Vec::into_parts(v); /// /// let rebuilt = unsafe { /// // We can now make changes to the components, such as @@ -1147,8 +1147,8 @@ impl Vec { #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_parts(self) -> (NonNull, usize, usize) { - let (ptr, len, capacity) = self.into_raw_parts(); + pub fn into_parts(vec: Self) -> (NonNull, usize, usize) { + let (ptr, len, capacity) = Self::into_raw_parts(vec); // SAFETY: A `Vec` always has a non-null pointer. (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) } @@ -1179,7 +1179,7 @@ impl Vec { /// v.push(0); /// v.push(1); /// - /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + /// let (ptr, len, cap, alloc) = Vec::into_raw_parts_with_alloc(v); /// /// let rebuilt = unsafe { /// // We can now make changes to the components, such as @@ -1193,8 +1193,8 @@ impl Vec { #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) { - let mut me = ManuallyDrop::new(self); + pub fn into_raw_parts_with_alloc(vec: Self) -> (*mut T, usize, usize, A) { + let mut me = ManuallyDrop::new(vec); let len = me.len(); let capacity = me.capacity(); let ptr = me.as_mut_ptr(); @@ -1229,7 +1229,7 @@ impl Vec { /// v.push(0); /// v.push(1); /// - /// let (ptr, len, cap, alloc) = v.into_parts_with_alloc(); + /// let (ptr, len, cap, alloc) = Vec::into_parts_with_alloc(v); /// /// let rebuilt = unsafe { /// // We can now make changes to the components, such as @@ -1244,8 +1244,8 @@ impl Vec { #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] - pub fn into_parts_with_alloc(self) -> (NonNull, usize, usize, A) { - let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc(); + pub fn into_parts_with_alloc(vec: Self) -> (NonNull, usize, usize, A) { + let (ptr, len, capacity, alloc) = Vec::into_raw_parts_with_alloc(vec); // SAFETY: A `Vec` always has a non-null pointer. (unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc) } @@ -3139,7 +3139,7 @@ impl Vec<[T; N], A> { /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] pub fn into_flattened(self) -> Vec { - let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc(); + let (ptr, len, cap, alloc) = Vec::into_raw_parts_with_alloc(self); let (new_len, new_cap) = if T::IS_ZST { (len.checked_mul(N).expect("vec len overflow"), usize::MAX) } else {