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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy