mod.rs - source
Description: Source of the Rust file `library/core/src/alloc/mod.rs`.

#
core/alloc/
mod.rs

    1//! Memory allocation APIs
    2
    3#![stable(feature = "alloc_module", since = "1.28.0")]
    4
    5mod global;
    6mod layout;
    7
    8#[stable(feature = "global_alloc", since = "1.28.0")]
    9pub use self::global::GlobalAlloc;
    10#[stable(feature = "alloc_layout", since = "1.28.0")]
    11pub use self::layout::Layout;
    12#[stable(feature = "alloc_layout", since = "1.28.0")]
    13#[deprecated(
    14    since = "1.52.0",
    15    note = "Name does not follow std convention, use LayoutError",
    16    suggestion = "LayoutError"
    17)]
    18#[allow(deprecated, deprecated_in_future)]
    19pub use self::layout::LayoutErr;
    20#[stable(feature = "alloc_layout_error", since = "1.50.0")]
    21pub use self::layout::LayoutError;
    22use crate::error::Error;
    23use crate::fmt;
    24use crate::ptr::{self, NonNull};
    25
    26/// The `AllocError` error indicates an allocation failure
    27/// that may be due to resource exhaustion or to
    28/// something wrong when combining the given input arguments with this
    29/// allocator.
    30#[unstable(feature = "allocator_api", issue = "32838")]
    31#[derive(Copy, Clone, PartialEq, Eq, Debug)]
    32pub struct AllocError;
    33
    34#[unstable(
    35    feature = "allocator_api",
    36    reason = "the precise API and guarantees it provides may be tweaked.",
    37    issue = "32838"
    38)]
    39impl Error for AllocError {}
    40
    41// (we need this for downstream impl of trait Error)
    42#[unstable(feature = "allocator_api", issue = "32838")]
    43impl fmt::Display for AllocError {
    44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    45        f.write_str("memory allocation failed")
    46    }
    47}
    48
    49/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
    50/// data described via [`Layout`][].
    51///
    52/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers.
    53/// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
    54/// allocated memory.
    55///
    56/// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying
    57/// allocator does not support this (like jemalloc) or responds by returning a null pointer
    58/// (such as `libc::malloc`), this must be caught by the implementation.
    59///
    60/// ### Currently allocated memory
    61///
    62/// Some of the methods require that a memory block is *currently allocated* by an allocator.
    63/// This means that:
    64///  * the starting address for that memory block was previously
    65///    returned by [`allocate`], [`grow`], or [`shrink`], and
    66///  * the memory block has not subsequently been deallocated.
    67///
    68/// A memory block is deallocated by a call to [`deallocate`],
    69/// or by a call to [`grow`] or [`shrink`] that returns `Ok`.
    70/// A call to `grow` or `shrink` that returns `Err`,
    71/// does not deallocate the memory block passed to it.
    72///
    73/// [`allocate`]: Allocator::allocate
    74/// [`grow`]: Allocator::grow
    75/// [`shrink`]: Allocator::shrink
    76/// [`deallocate`]: Allocator::deallocate
    77///
    78/// ### Memory fitting
    79///
    80/// Some of the methods require that a `layout` *fit* a memory block or vice versa. This means that the
    81/// following conditions must hold:
    82///  * the memory block must be *currently allocated* with alignment of [`layout.align()`], and
    83///  * [`layout.size()`] must fall in the range `min ..= max`, where:
    84///    - `min` is the size of the layout used to allocate the block, and
    85///    - `max` is the actual size returned from [`allocate`], [`grow`], or [`shrink`].
    86///
    87/// [`layout.align()`]: Layout::align
    88/// [`layout.size()`]: Layout::size
    89///
    90/// # Safety
    91///
    92/// Memory blocks that are [*currently allocated*] by an allocator,
    93/// must point to valid memory, and retain their validity until either:
    94///  - the memory block is deallocated, or
    95///  - the allocator is dropped.
    96///
    97/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it.
    98/// A copied or cloned allocator must behave like the original allocator.
    99///
    100/// A memory block which is [*currently allocated*] may be passed to
    101/// any method of the allocator that accepts such an argument.
    102///
    103/// [*currently allocated*]: #currently-allocated-memory
    104#[unstable(feature = "allocator_api", issue = "32838")]
    105#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
    106pub const unsafe trait Allocator {
    107    /// Attempts to allocate a block of memory.
    108    ///
    109    /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
    110    ///
    111    /// The returned block may have a larger size than specified by `layout.size()`, and may or may
    112    /// not have its contents initialized.
    113    ///
    114    /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of:
    115    ///   - the borrow-checker lifetime of the allocator type itself.
    116    ///   - as long as the allocator and all its clones have not been dropped.
    117    ///
    118    /// [*currently allocated*]: #currently-allocated-memory
    119    ///
    120    /// # Errors
    121    ///
    122    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    123    /// allocator's size or alignment constraints.
    124    ///
    125    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    126    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    127    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    128    ///
    129    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    130    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    131    ///
    132    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    133    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
    134
    135    /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
    136    ///
    137    /// # Errors
    138    ///
    139    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    140    /// allocator's size or alignment constraints.
    141    ///
    142    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    143    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    144    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    145    ///
    146    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    147    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    148    ///
    149    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    150    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    151        let ptr = self.allocate(layout)?;
    152        // SAFETY: `alloc` returns a valid memory block
    153        unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) }
    154        Ok(ptr)
    155    }
    156
    157    /// Deallocates the memory referenced by `ptr`.
    158    ///
    159    /// # Safety
    160    ///
    161    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
    162    /// * `layout` must [*fit*] that block of memory.
    163    ///
    164    /// [*currently allocated*]: #currently-allocated-memory
    165    /// [*fit*]: #memory-fitting
    166    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
    167
    168    /// Attempts to extend the memory block.
    169    ///
    170    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
    171    /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
    172    /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
    173    ///
    174    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    175    /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
    176    /// allocation was grown in-place. The newly returned pointer is the only valid pointer
    177    /// for accessing this memory now.
    178    ///
    179    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    180    /// this allocator, and the contents of the memory block are unaltered.
    181    ///
    182    /// # Safety
    183    ///
    184    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    185    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    186    /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
    187    ///
    188    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    189    ///
    190    /// [*currently allocated*]: #currently-allocated-memory
    191    /// [*fit*]: #memory-fitting
    192    ///
    193    /// # Errors
    194    ///
    195    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    196    /// constraints of the allocator, or if growing otherwise fails.
    197    ///
    198    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    199    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    200    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    201    ///
    202    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    203    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    204    ///
    205    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    206    unsafe fn grow(
    207        &self,
    208        ptr: NonNull<u8>,
    209        old_layout: Layout,
    210        new_layout: Layout,
    211    ) -> Result<NonNull<[u8]>, AllocError> {
    212        debug_assert!(
    213            new_layout.size() >= old_layout.size(),
    214            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
    215        );
    216
    217        let new_ptr = self.allocate(new_layout)?;
    218
    219        // SAFETY: because `new_layout.size()` must be greater than or equal to
    220        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    221        // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
    222        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    223        // safe. The safety contract for `dealloc` must be upheld by the caller.
    224        unsafe {
    225            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
    226            self.deallocate(ptr, old_layout);
    227        }
    228
    229        Ok(new_ptr)
    230    }
    231
    232    /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
    233    /// returned.
    234    ///
    235    /// The memory block will contain the following contents after a successful call to
    236    /// `grow_zeroed`:
    237    ///   * Bytes `0..old_layout.size()` are preserved from the original allocation.
    238    ///   * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
    239    ///     the allocator implementation. `old_size` refers to the size of the memory block prior
    240    ///     to the `grow_zeroed` call, which may be larger than the size that was originally
    241    ///     requested when it was allocated.
    242    ///   * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
    243    ///     block returned by the `grow_zeroed` call.
    244    ///
    245    /// # Safety
    246    ///
    247    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    248    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    249    /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
    250    ///
    251    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    252    ///
    253    /// [*currently allocated*]: #currently-allocated-memory
    254    /// [*fit*]: #memory-fitting
    255    ///
    256    /// # Errors
    257    ///
    258    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    259    /// constraints of the allocator, or if growing otherwise fails.
    260    ///
    261    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    262    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    263    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    264    ///
    265    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    266    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    267    ///
    268    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    269    unsafe fn grow_zeroed(
    270        &self,
    271        ptr: NonNull<u8>,
    272        old_layout: Layout,
    273        new_layout: Layout,
    274    ) -> Result<NonNull<[u8]>, AllocError> {
    275        debug_assert!(
    276            new_layout.size() >= old_layout.size(),
    277            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
    278        );
    279
    280        let new_ptr = self.allocate_zeroed(new_layout)?;
    281
    282        // SAFETY: because `new_layout.size()` must be greater than or equal to
    283        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    284        // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
    285        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    286        // safe. The safety contract for `dealloc` must be upheld by the caller.
    287        unsafe {
    288            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
    289            self.deallocate(ptr, old_layout);
    290        }
    291
    292        Ok(new_ptr)
    293    }
    294
    295    /// Attempts to shrink the memory block.
    296    ///
    297    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
    298    /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
    299    /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
    300    ///
    301    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    302    /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
    303    /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer
    304    /// for accessing this memory now.
    305    ///
    306    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    307    /// this allocator, and the contents of the memory block are unaltered.
    308    ///
    309    /// # Safety
    310    ///
    311    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    312    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    313    /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
    314    ///
    315    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    316    ///
    317    /// [*currently allocated*]: #currently-allocated-memory
    318    /// [*fit*]: #memory-fitting
    319    ///
    320    /// # Errors
    321    ///
    322    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    323    /// constraints of the allocator, or if shrinking otherwise fails.
    324    ///
    325    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    326    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    327    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    328    ///
    329    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    330    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    331    ///
    332    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    333    unsafe fn shrink(
    334        &self,
    335        ptr: NonNull<u8>,
    336        old_layout: Layout,
    337        new_layout: Layout,
    338    ) -> Result<NonNull<[u8]>, AllocError> {
    339        debug_assert!(
    340            new_layout.size() <= old_layout.size(),
    341            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
    342        );
    343
    344        let new_ptr = self.allocate(new_layout)?;
    345
    346        // SAFETY: because `new_layout.size()` must be lower than or equal to
    347        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    348        // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
    349        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    350        // safe. The safety contract for `dealloc` must be upheld by the caller.
    351        unsafe {
    352            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size());
    353            self.deallocate(ptr, old_layout);
    354        }
    355
    356        Ok(new_ptr)
    357    }
    358
    359    /// Creates a "by reference" adapter for this instance of `Allocator`.
    360    ///
    361    /// The returned adapter also implements `Allocator` and will simply borrow this.
    362    #[inline(always)]
    363    fn by_ref(&self) -> &Self
    364    where
    365        Self: Sized,
    366    {
    367        self
    368    }
    369}
    370
    371#[unstable(feature = "allocator_api", issue = "32838")]
    372#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
    373unsafe impl<A> const Allocator for &A
    374where
    375    A: [const] Allocator + ?Sized,
    376{
    377    #[inline]
    378    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    379        (**self).allocate(layout)
    380    }
    381
    382    #[inline]
    383    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    384        (**self).allocate_zeroed(layout)
    385    }
    386
    387    #[inline]
    388    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
    389        // SAFETY: the safety contract must be upheld by the caller
    390        unsafe { (**self).deallocate(ptr, layout) }
    391    }
    392
    393    #[inline]
    394    unsafe fn grow(
    395        &self,
    396        ptr: NonNull<u8>,
    397        old_layout: Layout,
    398        new_layout: Layout,
    399    ) -> Result<NonNull<[u8]>, AllocError> {
    400        // SAFETY: the safety contract must be upheld by the caller
    401        unsafe { (**self).grow(ptr, old_layout, new_layout) }
    402    }
    403
    404    #[inline]
    405    unsafe fn grow_zeroed(
    406        &self,
    407        ptr: NonNull<u8>,
    408        old_layout: Layout,
    409        new_layout: Layout,
    410    ) -> Result<NonNull<[u8]>, AllocError> {
    411        // SAFETY: the safety contract must be upheld by the caller
    412        unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
    413    }
    414
    415    #[inline]
    416    unsafe fn shrink(
    417        &self,
    418        ptr: NonNull<u8>,
    419        old_layout: Layout,
    420        new_layout: Layout,
    421    ) -> Result<NonNull<[u8]>, AllocError> {
    422        // SAFETY: the safety contract must be upheld by the caller
    423        unsafe { (**self).shrink(ptr, old_layout, new_layout) }
    424    }
    425}
    426
    427#[unstable(feature = "allocator_api", issue = "32838")]
    428unsafe impl<A> Allocator for &mut A
    429where
    430    A: Allocator + ?Sized,
    431{
    432    #[inline]
    433    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    434        (**self).allocate(layout)
    435    }
    436
    437    #[inline]
    438    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    439        (**self).allocate_zeroed(layout)
    440    }
    441
    442    #[inline]
    443    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
    444        // SAFETY: the safety contract must be upheld by the caller
    445        unsafe { (**self).deallocate(ptr, layout) }
    446    }
    447
    448    #[inline]
    449    unsafe fn grow(
    450        &self,
    451        ptr: NonNull<u8>,
    452        old_layout: Layout,
    453        new_layout: Layout,
    454    ) -> Result<NonNull<[u8]>, AllocError> {
    455        // SAFETY: the safety contract must be upheld by the caller
    456        unsafe { (**self).grow(ptr, old_layout, new_layout) }
    457    }
    458
    459    #[inline]
    460    unsafe fn grow_zeroed(
    461        &self,
    462        ptr: NonNull<u8>,
    463        old_layout: Layout,
    464        new_layout: Layout,
    465    ) -> Result<NonNull<[u8]>, AllocError> {
    466        // SAFETY: the safety contract must be upheld by the caller
    467        unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
    468    }
    469
    470    #[inline]
    471    unsafe fn shrink(
    472        &self,
    473        ptr: NonNull<u8>,
    474        old_layout: Layout,
    475        new_layout: Layout,
    476    ) -> Result<NonNull<[u8]>, AllocError> {
    477        // SAFETY: the safety contract must be upheld by the caller
    478        unsafe { (**self).shrink(ptr, old_layout, new_layout) }
    479    }
    480}