core/alloc/
global.rs

1use crate::alloc::Layout;
2use crate::{cmp, ptr};
3
4/// A memory allocator that can be registered as the standard library’s default
5/// through the `#[global_allocator]` attribute.
6///
7/// Some of the methods require that a memory block be *currently
8/// allocated* via an allocator. This means that:
9///
10/// * the starting address for that memory block was previously
11///   returned by a previous call to an allocation method
12///   such as `alloc`, and
13///
14/// * the memory block has not been subsequently deallocated, where
15///   blocks are deallocated either by being passed to a deallocation
16///   method such as `dealloc` or by being
17///   passed to a reallocation method that returns a non-null pointer.
18///
19///
20/// # Example
21///
22/// ```
23/// use std::alloc::{GlobalAlloc, Layout};
24/// use std::cell::UnsafeCell;
25/// use std::ptr::null_mut;
26/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
27///
28/// const ARENA_SIZE: usize = 128 * 1024;
29/// const MAX_SUPPORTED_ALIGN: usize = 4096;
30/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
31/// struct SimpleAllocator {
32///     arena: UnsafeCell<[u8; ARENA_SIZE]>,
33///     remaining: AtomicUsize, // we allocate from the top, counting down
34/// }
35///
36/// #[global_allocator]
37/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
38///     arena: UnsafeCell::new([0x55; ARENA_SIZE]),
39///     remaining: AtomicUsize::new(ARENA_SIZE),
40/// };
41///
42/// unsafe impl Sync for SimpleAllocator {}
43///
44/// unsafe impl GlobalAlloc for SimpleAllocator {
45///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
46///         let size = layout.size();
47///         let align = layout.align();
48///
49///         // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
50///         // So we can safely use a mask to ensure alignment without worrying about UB.
51///         let align_mask_to_round_down = !(align - 1);
52///
53///         if align > MAX_SUPPORTED_ALIGN {
54///             return null_mut();
55///         }
56///
57///         let mut allocated = 0;
58///         if self
59///             .remaining
60///             .fetch_update(Relaxed, Relaxed, |mut remaining| {
61///                 if size > remaining {
62///                     return None;
63///                 }
64///                 remaining -= size;
65///                 remaining &= align_mask_to_round_down;
66///                 allocated = remaining;
67///                 Some(remaining)
68///             })
69///             .is_err()
70///         {
71///             return null_mut();
72///         };
73///         unsafe { self.arena.get().cast::<u8>().add(allocated) }
74///     }
75///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
76/// }
77///
78/// fn main() {
79///     let _s = format!("allocating a string!");
80///     let currently = ALLOCATOR.remaining.load(Relaxed);
81///     println!("allocated so far: {}", ARENA_SIZE - currently);
82/// }
83/// ```
84///
85/// # Safety
86///
87/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
88/// implementors must ensure that they adhere to these contracts:
89///
90/// * It's undefined behavior if global allocators unwind. This restriction may
91///   be lifted in the future, but currently a panic from any of these
92///   functions may lead to memory unsafety.
93///
94/// * `Layout` queries and calculations in general must be correct. Callers of
95///   this trait are allowed to rely on the contracts defined on each method,
96///   and implementors must ensure such contracts remain true.
97///
98/// * You must not rely on allocations actually happening, even if there are explicit
99///   heap allocations in the source. The optimizer may detect unused allocations that it can either
100///   eliminate entirely or move to the stack and thus never invoke the allocator. The
101///   optimizer may further assume that allocation is infallible, so code that used to fail due
102///   to allocator failures may now suddenly work because the optimizer worked around the
103///   need for an allocation. More concretely, the following code example is unsound, irrespective
104///   of whether your custom allocator allows counting how many allocations have happened.
105///
106///   ```rust,ignore (unsound and has placeholders)
107///   drop(Box::new(42));
108///   let number_of_heap_allocs = /* call private allocator API */;
109///   unsafe { std::hint::assert_unchecked(number_of_heap_allocs > 0); }
110///   ```
111///
112///   Note that the optimizations mentioned above are not the only
113///   optimization that can be applied. You may generally not rely on heap allocations
114///   happening if they can be removed without changing program behavior.
115///   Whether allocations happen or not is not part of the program behavior, even if it
116///   could be detected via an allocator that tracks allocations by printing or otherwise
117///   having side effects.
118#[stable(feature = "global_alloc", since = "1.28.0")]
119pub unsafe trait GlobalAlloc {
120    /// Allocates memory as described by the given `layout`.
121    ///
122    /// Returns a pointer to newly-allocated memory,
123    /// or null to indicate allocation failure.
124    ///
125    /// # Safety
126    ///
127    /// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may
128    /// result in undefined behavior.
129    ///
130    /// (Extension subtraits might provide more specific bounds on
131    /// behavior, e.g., guarantee a sentinel address or a null pointer
132    /// in response to a zero-size allocation request.)
133    ///
134    /// The allocated block of memory may or may not be initialized.
135    ///
136    /// # Errors
137    ///
138    /// Returning a null pointer indicates that either memory is exhausted
139    /// or `layout` does not meet this allocator's size or alignment constraints.
140    ///
141    /// Implementations are encouraged to return null on memory
142    /// exhaustion rather than aborting, but this is not
143    /// a strict requirement. (Specifically: it is *legal* to
144    /// implement this trait atop an underlying native allocation
145    /// library that aborts on memory exhaustion.)
146    ///
147    /// Clients wishing to abort computation in response to an
148    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
149    /// rather than directly invoking `panic!` or similar.
150    ///
151    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
152    #[stable(feature = "global_alloc", since = "1.28.0")]
153    unsafe fn alloc(&self, layout: Layout) -> *mut u8;
154
155    /// Deallocates the block of memory at the given `ptr` pointer with the given `layout`.
156    ///
157    /// # Safety
158    ///
159    /// The caller must ensure:
160    ///
161    /// * `ptr` is a block of memory currently allocated via this allocator and,
162    ///
163    /// * `layout` is the same layout that was used to allocate that block of
164    ///   memory.
165    ///
166    /// Otherwise undefined behavior can result.
167    #[stable(feature = "global_alloc", since = "1.28.0")]
168    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
169
170    /// Behaves like `alloc`, but also ensures that the contents
171    /// are set to zero before being returned.
172    ///
173    /// # Safety
174    ///
175    /// The caller has to ensure that `layout` has non-zero size. Like `alloc`
176    /// zero sized `layout` can result in undefined behavior.
177    /// However the allocated block of memory is guaranteed to be initialized.
178    ///
179    /// # Errors
180    ///
181    /// Returning a null pointer indicates that either memory is exhausted
182    /// or `layout` does not meet allocator's size or alignment constraints,
183    /// just as in `alloc`.
184    ///
185    /// Clients wishing to abort computation in response to an
186    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
187    /// rather than directly invoking `panic!` or similar.
188    ///
189    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
190    #[stable(feature = "global_alloc", since = "1.28.0")]
191    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
192        let size = layout.size();
193        // SAFETY: the safety contract for `alloc` must be upheld by the caller.
194        let ptr = unsafe { self.alloc(layout) };
195        if !ptr.is_null() {
196            // SAFETY: as allocation succeeded, the region from `ptr`
197            // of size `size` is guaranteed to be valid for writes.
198            unsafe { ptr::write_bytes(ptr, 0, size) };
199        }
200        ptr
201    }
202
203    /// Shrinks or grows a block of memory to the given `new_size` in bytes.
204    /// The block is described by the given `ptr` pointer and `layout`.
205    ///
206    /// If this returns a non-null pointer, then ownership of the memory block
207    /// referenced by `ptr` has been transferred to this allocator.
208    /// Any access to the old `ptr` is Undefined Behavior, even if the
209    /// allocation remained in-place. The newly returned pointer is the only valid pointer
210    /// for accessing this memory now.
211    ///
212    /// The new memory block is allocated with `layout`,
213    /// but with the `size` updated to `new_size` in bytes.
214    /// This new layout must be used when deallocating the new memory block with `dealloc`.
215    /// The range `0..min(layout.size(), new_size)` of the new memory block is
216    /// guaranteed to have the same values as the original block.
217    ///
218    /// If this method returns null, then ownership of the memory
219    /// block has not been transferred to this allocator, and the
220    /// contents of the memory block are unaltered.
221    ///
222    /// # Safety
223    ///
224    /// The caller must ensure that:
225    ///
226    /// * `ptr` is allocated via this allocator,
227    ///
228    /// * `layout` is the same layout that was used
229    ///   to allocate that block of memory,
230    ///
231    /// * `new_size` is greater than zero.
232    ///
233    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
234    ///   does not overflow `isize` (i.e., the rounded value must be less than or
235    ///   equal to `isize::MAX`).
236    ///
237    /// If these are not followed, undefined behavior can result.
238    ///
239    /// (Extension subtraits might provide more specific bounds on
240    /// behavior, e.g., guarantee a sentinel address or a null pointer
241    /// in response to a zero-size allocation request.)
242    ///
243    /// # Errors
244    ///
245    /// Returns null if the new layout does not meet the size
246    /// and alignment constraints of the allocator, or if reallocation
247    /// otherwise fails.
248    ///
249    /// Implementations are encouraged to return null on memory
250    /// exhaustion rather than panicking or aborting, but this is not
251    /// a strict requirement. (Specifically: it is *legal* to
252    /// implement this trait atop an underlying native allocation
253    /// library that aborts on memory exhaustion.)
254    ///
255    /// Clients wishing to abort computation in response to a
256    /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
257    /// rather than directly invoking `panic!` or similar.
258    ///
259    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
260    #[stable(feature = "global_alloc", since = "1.28.0")]
261    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
262        // SAFETY: the caller must ensure that the `new_size` does not overflow.
263        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
264        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
265        // SAFETY: the caller must ensure that `new_layout` is greater than zero.
266        let new_ptr = unsafe { self.alloc(new_layout) };
267        if !new_ptr.is_null() {
268            // SAFETY: the previously allocated block cannot overlap the newly allocated block.
269            // The safety contract for `dealloc` must be upheld by the caller.
270            unsafe {
271                ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
272                self.dealloc(ptr, layout);
273            }
274        }
275        new_ptr
276    }
277}
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