#
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")]
    105pub unsafe trait Allocator {
    106    /// Attempts to allocate a block of memory.
    107    ///
    108    /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
    109    ///
    110    /// The returned block may have a larger size than specified by `layout.size()`, and may or may
    111    /// not have its contents initialized.
    112    ///
    113    /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of:
    114    ///   - the borrow-checker lifetime of the allocator type itself.
    115    ///   - as long as the allocator and all its clones have not been dropped.
    116    ///
    117    /// [*currently allocated*]: #currently-allocated-memory
    118    ///
    119    /// # Errors
    120    ///
    121    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    122    /// allocator's size or alignment constraints.
    123    ///
    124    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    125    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    126    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    127    ///
    128    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    129    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    130    ///
    131    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    132    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
    133
    134    /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
    135    ///
    136    /// # Errors
    137    ///
    138    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    139    /// allocator's size or alignment constraints.
    140    ///
    141    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    142    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    143    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    144    ///
    145    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    146    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    147    ///
    148    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    149    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    150        let ptr = self.allocate(layout)?;
    151        // SAFETY: `alloc` returns a valid memory block
    152        unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) }
    153        Ok(ptr)
    154    }
    155
    156    /// Deallocates the memory referenced by `ptr`.
    157    ///
    158    /// # Safety
    159    ///
    160    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
    161    /// * `layout` must [*fit*] that block of memory.
    162    ///
    163    /// [*currently allocated*]: #currently-allocated-memory
    164    /// [*fit*]: #memory-fitting
    165    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
    166
    167    /// Attempts to extend the memory block.
    168    ///
    169    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
    170    /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
    171    /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
    172    ///
    173    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    174    /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
    175    /// allocation was grown in-place. The newly returned pointer is the only valid pointer
    176    /// for accessing this memory now.
    177    ///
    178    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    179    /// this allocator, and the contents of the memory block are unaltered.
    180    ///
    181    /// # Safety
    182    ///
    183    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    184    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    185    /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
    186    ///
    187    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    188    ///
    189    /// [*currently allocated*]: #currently-allocated-memory
    190    /// [*fit*]: #memory-fitting
    191    ///
    192    /// # Errors
    193    ///
    194    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    195    /// constraints of the allocator, or if growing otherwise fails.
    196    ///
    197    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    198    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    199    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    200    ///
    201    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    202    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    203    ///
    204    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    205    unsafe fn grow(
    206        &self,
    207        ptr: NonNull<u8>,
    208        old_layout: Layout,
    209        new_layout: Layout,
    210    ) -> Result<NonNull<[u8]>, AllocError> {
    211        debug_assert!(
    212            new_layout.size() >= old_layout.size(),
    213            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
    214        );
    215
    216        let new_ptr = self.allocate(new_layout)?;
    217
    218        // SAFETY: because `new_layout.size()` must be greater than or equal to
    219        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    220        // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
    221        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    222        // safe. The safety contract for `dealloc` must be upheld by the caller.
    223        unsafe {
    224            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
    225            self.deallocate(ptr, old_layout);
    226        }
    227
    228        Ok(new_ptr)
    229    }
    230
    231    /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
    232    /// returned.
    233    ///
    234    /// The memory block will contain the following contents after a successful call to
    235    /// `grow_zeroed`:
    236    ///   * Bytes `0..old_layout.size()` are preserved from the original allocation.
    237    ///   * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
    238    ///     the allocator implementation. `old_size` refers to the size of the memory block prior
    239    ///     to the `grow_zeroed` call, which may be larger than the size that was originally
    240    ///     requested when it was allocated.
    241    ///   * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
    242    ///     block returned by the `grow_zeroed` call.
    243    ///
    244    /// # Safety
    245    ///
    246    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    247    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    248    /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
    249    ///
    250    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    251    ///
    252    /// [*currently allocated*]: #currently-allocated-memory
    253    /// [*fit*]: #memory-fitting
    254    ///
    255    /// # Errors
    256    ///
    257    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    258    /// constraints of the allocator, or if growing otherwise fails.
    259    ///
    260    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    261    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    262    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    263    ///
    264    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    265    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    266    ///
    267    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    268    unsafe fn grow_zeroed(
    269        &self,
    270        ptr: NonNull<u8>,
    271        old_layout: Layout,
    272        new_layout: Layout,
    273    ) -> Result<NonNull<[u8]>, AllocError> {
    274        debug_assert!(
    275            new_layout.size() >= old_layout.size(),
    276            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
    277        );
    278
    279        let new_ptr = self.allocate_zeroed(new_layout)?;
    280
    281        // SAFETY: because `new_layout.size()` must be greater than or equal to
    282        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    283        // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
    284        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    285        // safe. The safety contract for `dealloc` must be upheld by the caller.
    286        unsafe {
    287            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
    288            self.deallocate(ptr, old_layout);
    289        }
    290
    291        Ok(new_ptr)
    292    }
    293
    294    /// Attempts to shrink the memory block.
    295    ///
    296    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
    297    /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
    298    /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
    299    ///
    300    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    301    /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
    302    /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer
    303    /// for accessing this memory now.
    304    ///
    305    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    306    /// this allocator, and the contents of the memory block are unaltered.
    307    ///
    308    /// # Safety
    309    ///
    310    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
    311    /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
    312    /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
    313    ///
    314    /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
    315    ///
    316    /// [*currently allocated*]: #currently-allocated-memory
    317    /// [*fit*]: #memory-fitting
    318    ///
    319    /// # Errors
    320    ///
    321    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    322    /// constraints of the allocator, or if shrinking otherwise fails.
    323    ///
    324    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    325    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    326    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    327    ///
    328    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    329    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    330    ///
    331    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    332    unsafe fn shrink(
    333        &self,
    334        ptr: NonNull<u8>,
    335        old_layout: Layout,
    336        new_layout: Layout,
    337    ) -> Result<NonNull<[u8]>, AllocError> {
    338        debug_assert!(
    339            new_layout.size() <= old_layout.size(),
    340            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
    341        );
    342
    343        let new_ptr = self.allocate(new_layout)?;
    344
    345        // SAFETY: because `new_layout.size()` must be lower than or equal to
    346        // `old_layout.size()`, both the old and new memory allocation are valid for reads and
    347        // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
    348        // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
    349        // safe. The safety contract for `dealloc` must be upheld by the caller.
    350        unsafe {
    351            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size());
    352            self.deallocate(ptr, old_layout);
    353        }
    354
    355        Ok(new_ptr)
    356    }
    357
    358    /// Creates a "by reference" adapter for this instance of `Allocator`.
    359    ///
    360    /// The returned adapter also implements `Allocator` and will simply borrow this.
    361    #[inline(always)]
    362    fn by_ref(&self) -> &Self
    363    where
    364        Self: Sized,
    365    {
    366        self
    367    }
    368}
    369
    370#[unstable(feature = "allocator_api", issue = "32838")]
    371unsafe impl<A> Allocator for &A
    372where
    373    A: Allocator + ?Sized,
    374{
    375    #[inline]
    376    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    377        (**self).allocate(layout)
    378    }
    379
    380    #[inline]
    381    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
    382        (**self).allocate_zeroed(layout)
    383    }
    384
    385    #[inline]
    386    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
    387        // SAFETY: the safety contract must be upheld by the caller
    388        unsafe { (**self).deallocate(ptr, layout) }
    389    }
    390
    391    #[inline]
    392    unsafe fn grow(
    393        &self,
    394        ptr: NonNull<u8>,
    395        old_layout: Layout,
    396        new_layout: Layout,
    397    ) -> Result<NonNull<[u8]>, AllocError> {
    398        // SAFETY: the safety contract must be upheld by the caller
    399        unsafe { (**self).grow(ptr, old_layout, new_layout) }
    400    }
    401
    402    #[inline]
    403    unsafe fn grow_zeroed(
    404        &self,
    405        ptr: NonNull<u8>,
    406        old_layout: Layout,
    407        new_layout: Layout,
    408    ) -> Result<NonNull<[u8]>, AllocError> {
    409        // SAFETY: the safety contract must be upheld by the caller
    410        unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
    411    }
    412
    413    #[inline]
    414    unsafe fn shrink(
    415        &self,
    416        ptr: NonNull<u8>,
    417        old_layout: Layout,
    418        new_layout: Layout,
    419    ) -> Result<NonNull<[u8]>, AllocError> {
    420        // SAFETY: the safety contract must be upheld by the caller
    421        unsafe { (**self).shrink(ptr, old_layout, new_layout) }
    422    }
    423}