Rollup merge of #99216 - duarten:master, r=joshtriplett

docs: be less harsh in wording for Vec::from_raw_parts

In particular, be clear that it is sound to specify memory not
originating from a previous `Vec` allocation. That is already suggested
in other parts of the documentation about zero-alloc conversions to Box<[T]>.

Incorporate a constraint from `slice::from_raw_parts` that was missing
but needs to be fulfilled, since a `Vec` can be converted into a slice.

Fixes https://github.com/rust-lang/rust/issues/98780.
This commit is contained in:
Matthias Krüger 2022-10-03 20:58:53 +02:00 committed by GitHub
commit 2110d2de5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 73 additions and 8 deletions

View File

@ -483,15 +483,13 @@ impl<T> Vec<T> {
Self::with_capacity_in(capacity, Global) Self::with_capacity_in(capacity, Global)
} }
/// Creates a `Vec<T>` directly from the raw components of another vector. /// Creates a `Vec<T>` directly from a pointer, a capacity, and a length.
/// ///
/// # Safety /// # Safety
/// ///
/// This is highly unsafe, due to the number of invariants that aren't /// This is highly unsafe, due to the number of invariants that aren't
/// checked: /// checked:
/// ///
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
/// (at least, it's highly likely to be incorrect if it wasn't).
/// * `T` needs to have the same alignment as what `ptr` was allocated with. /// * `T` needs to have the same alignment as what `ptr` was allocated with.
/// (`T` having a less strict alignment is not sufficient, the alignment really /// (`T` having a less strict alignment is not sufficient, the alignment really
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
@ -500,6 +498,14 @@ impl<T> Vec<T> {
/// to be the same size as the pointer was allocated with. (Because similar to /// to be the same size as the pointer was allocated with. (Because similar to
/// alignment, [`dealloc`] must be called with the same layout `size`.) /// alignment, [`dealloc`] must be called with the same layout `size`.)
/// * `length` needs to be less than or equal to `capacity`. /// * `length` needs to be less than or equal to `capacity`.
/// * The first `length` values must be properly initialized values of type `T`.
/// * `capacity` needs to be the capacity that the pointer was allocated with.
/// * The allocated size in bytes must be no larger than `isize::MAX`.
/// See the safety documentation of [`pointer::offset`].
///
/// These requirements are always upheld by any `ptr` that has been allocated
/// via `Vec<T>`. Other allocation sources are allowed if the invariants are
/// upheld.
/// ///
/// Violating these may cause problems like corrupting the allocator's /// Violating these may cause problems like corrupting the allocator's
/// internal data structures. For example it is normally **not** safe /// internal data structures. For example it is normally **not** safe
@ -551,6 +557,32 @@ impl<T> Vec<T> {
/// assert_eq!(rebuilt, [4, 5, 6]); /// assert_eq!(rebuilt, [4, 5, 6]);
/// } /// }
/// ``` /// ```
///
/// Using memory that was allocated elsewhere:
///
/// ```rust
/// #![feature(allocator_api)]
///
/// use std::alloc::{AllocError, Allocator, Global, Layout};
///
/// fn main() {
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
///
/// let vec = unsafe {
/// let mem = match Global.allocate(layout) {
/// Ok(mem) => mem.cast::<u32>().as_ptr(),
/// Err(AllocError) => return,
/// };
///
/// mem.write(1_000_000);
///
/// Vec::from_raw_parts_in(mem, 1, 16, Global)
/// };
///
/// assert_eq!(vec, &[1_000_000]);
/// assert_eq!(vec.capacity(), 16);
/// }
/// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
@ -641,21 +673,30 @@ impl<T, A: Allocator> Vec<T, A> {
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
} }
/// Creates a `Vec<T, A>` directly from the raw components of another vector. /// Creates a `Vec<T, A>` directly from a pointer, a capacity, a length,
/// and an allocator.
/// ///
/// # Safety /// # Safety
/// ///
/// This is highly unsafe, due to the number of invariants that aren't /// This is highly unsafe, due to the number of invariants that aren't
/// checked: /// checked:
/// ///
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>` /// * `T` needs to have the same alignment as what `ptr` was allocated with.
/// (at least, it's highly likely to be incorrect if it wasn't).
/// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
/// (`T` having a less strict alignment is not sufficient, the alignment really /// (`T` having a less strict alignment is not sufficient, the alignment really
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
/// allocated and deallocated with the same layout.) /// allocated and deallocated with the same layout.)
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
/// to be the same size as the pointer was allocated with. (Because similar to
/// alignment, [`dealloc`] must be called with the same layout `size`.)
/// * `length` needs to be less than or equal to `capacity`. /// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the capacity that the pointer was allocated with. /// * The first `length` values must be properly initialized values of type `T`.
/// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with.
/// * The allocated size in bytes must be no larger than `isize::MAX`.
/// See the safety documentation of [`pointer::offset`].
///
/// These requirements are always upheld by any `ptr` that has been allocated
/// via `Vec<T, A>`. Other allocation sources are allowed if the invariants are
/// upheld.
/// ///
/// Violating these may cause problems like corrupting the allocator's /// Violating these may cause problems like corrupting the allocator's
/// internal data structures. For example it is **not** safe /// internal data structures. For example it is **not** safe
@ -673,6 +714,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// ///
/// [`String`]: crate::string::String /// [`String`]: crate::string::String
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
/// [*fit*]: crate::alloc::Allocator#memory-fitting
/// ///
/// # Examples /// # Examples
/// ///
@ -711,6 +753,29 @@ impl<T, A: Allocator> Vec<T, A> {
/// assert_eq!(rebuilt, [4, 5, 6]); /// assert_eq!(rebuilt, [4, 5, 6]);
/// } /// }
/// ``` /// ```
///
/// Using memory that was allocated elsewhere:
///
/// ```rust
/// use std::alloc::{alloc, Layout};
///
/// fn main() {
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
/// let vec = unsafe {
/// let mem = alloc(layout).cast::<u32>();
/// if mem.is_null() {
/// return;
/// }
///
/// mem.write(1_000_000);
///
/// Vec::from_raw_parts(mem, 1, 16)
/// };
///
/// assert_eq!(vec, &[1_000_000]);
/// assert_eq!(vec.capacity(), 16);
/// }
/// ```
#[inline] #[inline]
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {