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