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}