Skip to content

Commit 1ce4b37

Browse files
committed
Handle the capacity == 0 case
1 parent 45e2449 commit 1ce4b37

File tree

1 file changed

+34
-27
lines changed

1 file changed

+34
-27
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,20 @@
5151
//!
5252
//! # Memory layout
5353
//!
54-
//! For non-zero-sized types, [`Vec`] uses the [`Global`] allocator for its allocation. It is
55-
//! valid to convert both ways between a [`Vec`] and a raw pointer allocated with the [`Global`]
56-
//! allocator, provided that the [`Layout`] used with the allocator is correct for a sequence of
57-
//! `capacity` elements of the type, and the first `len` values pointed to by the raw pointer are
58-
//! valid. More precisely, a `ptr: *mut T` that has been allocated with the [`Global`] allocator
59-
//! with [`Layout::array::<T>(capacity)`][Layout::array] may be converted into a vec using
60-
//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts).
61-
//! Conversely, the memory backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be
62-
//! deallocated using the [`Global`] allocator with the same layout.
54+
//! When the type is non-zero-sized and the capacity is nonzero, [`Vec`] uses the [`Global`]
55+
//! allocator for its allocation. It is valid to convert both ways between such a [`Vec`] and a raw
56+
//! pointer allocated with the [`Global`] allocator, provided that the [`Layout`] used with the
57+
//! allocator is correct for a sequence of `capacity` elements of the type, and the first `len`
58+
//! values pointed to by the raw pointer are valid. More precisely, a `ptr: *mut T` that has been
59+
//! allocated with the [`Global`] allocator with [`Layout::array::<T>(capacity)`][Layout::array] may
60+
//! be converted into a vec using
61+
//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). Conversely, the memory
62+
//! backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be deallocated using the
63+
//! [`Global`] allocator with the same layout.
6364
//!
64-
//! For zero-sized types (ZSTs), the `Vec` pointer must be non-null and sufficiently aligned.
65-
//! The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be used is to use
66-
//! [`ptr::NonNull::dangling`].
65+
//! For zero-sized types (ZSTs), or when the capacity is zero, the `Vec` pointer must be non-null
66+
//! and sufficiently aligned. The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be
67+
//! used is to use [`ptr::NonNull::dangling`].
6768
//!
6869
//! [`push`]: Vec::push
6970
//! [`ptr::NonNull::dangling`]: NonNull::dangling
@@ -542,18 +543,23 @@ impl<T> Vec<T> {
542543
/// This is highly unsafe, due to the number of invariants that aren't
543544
/// checked:
544545
///
545-
/// * `ptr` must have been allocated using the global allocator, such as via
546-
/// the [`alloc::alloc`] function.
547-
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
546+
/// * If `T` is not a zero-sized type and the capacity is nonzero, `ptr` must have
547+
/// been allocated using the global allocator, such as via the [`alloc::alloc`]
548+
/// function. If `T` is a zero-sized type or the capacity is zero, `ptr` need
549+
/// only be non-null and aligned.
550+
/// * `T` needs to have the same alignment as what `ptr` was allocated with,
551+
/// if the pointer is required to be allocated.
548552
/// (`T` having a less strict alignment is not sufficient, the alignment really
549553
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
550554
/// allocated and deallocated with the same layout.)
551-
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
552-
/// to be the same size as the pointer was allocated with. (Because similar to
553-
/// alignment, [`dealloc`] must be called with the same layout `size`.)
555+
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if
556+
/// nonzero, needs to be the same size as the pointer was allocated with.
557+
/// (Because similar to alignment, [`dealloc`] must be called with the same
558+
/// layout `size`.)
554559
/// * `length` needs to be less than or equal to `capacity`.
555560
/// * The first `length` values must be properly initialized values of type `T`.
556-
/// * `capacity` needs to be the capacity that the pointer was allocated with.
561+
/// * `capacity` needs to be the capacity that the pointer was allocated with,
562+
/// if the pointer is required to be allocated.
557563
/// * The allocated size in bytes must be no larger than `isize::MAX`.
558564
/// See the safety documentation of [`pointer::offset`].
559565
///
@@ -792,9 +798,10 @@ impl<T> Vec<T> {
792798
/// memory previously managed by the `Vec`. Most often, one does
793799
/// this by converting the raw pointer, length, and capacity back
794800
/// into a `Vec` with the [`from_raw_parts`] function; more generally,
795-
/// if `T` is non-zero-sized one may use any method that calls
796-
/// [`dealloc`] with a layout of `Layout::array::<T>(capacity)`,
797-
/// and if `T` is zero-sized nothing needs to be done.
801+
/// if `T` is non-zero-sized and the capacity is nonzero, one may use
802+
/// any method that calls [`dealloc`] with a layout of
803+
/// `Layout::array::<T>(capacity)`; if `T` is zero-sized or the
804+
/// capacity is zero, nothing needs to be done.
798805
///
799806
/// [`from_raw_parts`]: Vec::from_raw_parts
800807
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
@@ -1777,11 +1784,11 @@ impl<T, A: Allocator> Vec<T, A> {
17771784
/// may still invalidate this pointer.
17781785
/// See the second example below for how this guarantee can be used.
17791786
///
1780-
/// The method also guarantees that, as long as `T` is not zero-sized, the pointer may be
1781-
/// passed into [`dealloc`] with a layout of `Layout::array::<T>(capacity)` in order to
1782-
/// deallocate the backing memory. If this is done, be careful not to run the destructor
1783-
/// of the `Vec`, as dropping it will result in double-frees. Wrapping the `Vec` in a
1784-
/// [`ManuallyDrop`] is the typical way to achieve this.
1787+
/// The method also guarantees that, as long as `T` is not zero-sized and the capacity is
1788+
/// nonzero, the pointer may be passed into [`dealloc`] with a layout of
1789+
/// `Layout::array::<T>(capacity)` in order to deallocate the backing memory. If this is done,
1790+
/// be careful not to run the destructor of the `Vec`, as dropping it will result in
1791+
/// double-frees. Wrapping the `Vec` in a [`ManuallyDrop`] is the typical way to achieve this.
17851792
///
17861793
/// # Examples
17871794
///

0 commit comments

Comments
 (0)