1 use crate::alloc::Layout;
5 /// A memory allocator that can be registered as the standard library’s default
6 /// through the `#[global_allocator]` attribute.
8 /// Some of the methods require that a memory block be *currently
9 /// allocated* via an allocator. This means that:
11 /// * the starting address for that memory block was previously
12 /// returned by a previous call to an allocation method
13 /// such as `alloc`, and
15 /// * the memory block has not been subsequently deallocated, where
16 /// blocks are deallocated either by being passed to a deallocation
17 /// method such as `dealloc` or by being
18 /// passed to a reallocation method that returns a non-null pointer.
24 /// use std::alloc::{GlobalAlloc, Layout, alloc};
25 /// use std::ptr::null_mut;
27 /// struct MyAllocator;
29 /// unsafe impl GlobalAlloc for MyAllocator {
30 /// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
31 /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
34 /// #[global_allocator]
35 /// static A: MyAllocator = MyAllocator;
39 /// assert!(alloc(Layout::new::<u32>()).is_null())
46 /// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
47 /// implementors must ensure that they adhere to these contracts:
49 /// * It's undefined behavior if global allocators unwind. This restriction may
50 /// be lifted in the future, but currently a panic from any of these
51 /// functions may lead to memory unsafety.
53 /// * `Layout` queries and calculations in general must be correct. Callers of
54 /// this trait are allowed to rely on the contracts defined on each method,
55 /// and implementors must ensure such contracts remain true.
57 /// * You may not rely on allocations actually happening, even if there are explicit
58 /// heap allocations in the source.
59 /// The optimizer may detect unused allocations that it can either
60 /// eliminate entirely or move to the stack and thus never invoke the allocator. The
61 /// optimizer may further assume that allocation is infallible, so code that used to fail due
62 /// to allocator failures may now suddenly work because the optimizer worked around the
63 /// need for an allocation.
64 /// More concretely, the following code example is unsound, irrespective of whether your
65 /// custom allocator allows counting how many allocations have happened.
67 /// ```rust,ignore (unsound and has placeholders)
68 /// drop(Box::new(42));
69 /// let number_of_heap_allocs = /* call private allocator API */;
70 /// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
73 /// Note that the optimizations mentioned above are not the only
74 /// optimization that can be applied. You may generally not rely on heap allocations
75 /// happening if they can be removed without changing program behavior.
76 /// Whether allocations happen or not is not part of the program behavior, even if it
77 /// could be detected via an allocator that tracks allocations by printing or otherwise
78 /// having side effects.
79 #[stable(feature = "global_alloc", since = "1.28.0")]
80 pub unsafe trait GlobalAlloc {
81 /// Allocate memory as described by the given `layout`.
83 /// Returns a pointer to newly-allocated memory,
84 /// or null to indicate allocation failure.
88 /// This function is unsafe because undefined behavior can result
89 /// if the caller does not ensure that `layout` has non-zero size.
91 /// (Extension subtraits might provide more specific bounds on
92 /// behavior, e.g., guarantee a sentinel address or a null pointer
93 /// in response to a zero-size allocation request.)
95 /// The allocated block of memory may or may not be initialized.
99 /// Returning a null pointer indicates that either memory is exhausted
100 /// or `layout` does not meet this allocator's size or alignment constraints.
102 /// Implementations are encouraged to return null on memory
103 /// exhaustion rather than aborting, but this is not
104 /// a strict requirement. (Specifically: it is *legal* to
105 /// implement this trait atop an underlying native allocation
106 /// library that aborts on memory exhaustion.)
108 /// Clients wishing to abort computation in response to an
109 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
110 /// rather than directly invoking `panic!` or similar.
112 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
113 #[stable(feature = "global_alloc", since = "1.28.0")]
114 unsafe fn alloc(&self, layout: Layout) -> *mut u8;
116 /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
120 /// This function is unsafe because undefined behavior can result
121 /// if the caller does not ensure all of the following:
123 /// * `ptr` must denote a block of memory currently allocated via
126 /// * `layout` must be the same layout that was used
127 /// to allocate that block of memory,
128 #[stable(feature = "global_alloc", since = "1.28.0")]
129 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
131 /// Behaves like `alloc`, but also ensures that the contents
132 /// are set to zero before being returned.
136 /// This function is unsafe for the same reasons that `alloc` is.
137 /// However the allocated block of memory is guaranteed to be initialized.
141 /// Returning a null pointer indicates that either memory is exhausted
142 /// or `layout` does not meet allocator's size or alignment constraints,
143 /// just as in `alloc`.
145 /// Clients wishing to abort computation in response to an
146 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
147 /// rather than directly invoking `panic!` or similar.
149 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
150 #[stable(feature = "global_alloc", since = "1.28.0")]
151 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
152 let size = layout.size();
153 // SAFETY: the safety contract for `alloc` must be upheld by the caller.
154 let ptr = unsafe { self.alloc(layout) };
156 // SAFETY: as allocation succeeded, the region from `ptr`
157 // of size `size` is guaranteed to be valid for writes.
158 unsafe { ptr::write_bytes(ptr, 0, size) };
163 /// Shrink or grow a block of memory to the given `new_size`.
164 /// The block is described by the given `ptr` pointer and `layout`.
166 /// If this returns a non-null pointer, then ownership of the memory block
167 /// referenced by `ptr` has been transferred to this allocator.
168 /// The memory may or may not have been deallocated,
169 /// and should be considered unusable (unless of course it was
170 /// transferred back to the caller again via the return value of
171 /// this method). The new memory block is allocated with `layout`, but
172 /// with the `size` updated to `new_size`.
174 /// If this method returns null, then ownership of the memory
175 /// block has not been transferred to this allocator, and the
176 /// contents of the memory block are unaltered.
180 /// This function is unsafe because undefined behavior can result
181 /// if the caller does not ensure all of the following:
183 /// * `ptr` must be currently allocated via this allocator,
185 /// * `layout` must be the same layout that was used
186 /// to allocate that block of memory,
188 /// * `new_size` must be greater than zero.
190 /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
191 /// must not overflow (i.e., the rounded value must be less than `usize::MAX`).
193 /// (Extension subtraits might provide more specific bounds on
194 /// behavior, e.g., guarantee a sentinel address or a null pointer
195 /// in response to a zero-size allocation request.)
199 /// Returns null if the new layout does not meet the size
200 /// and alignment constraints of the allocator, or if reallocation
203 /// Implementations are encouraged to return null on memory
204 /// exhaustion rather than panicking or aborting, but this is not
205 /// a strict requirement. (Specifically: it is *legal* to
206 /// implement this trait atop an underlying native allocation
207 /// library that aborts on memory exhaustion.)
209 /// Clients wishing to abort computation in response to a
210 /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
211 /// rather than directly invoking `panic!` or similar.
213 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
214 #[stable(feature = "global_alloc", since = "1.28.0")]
215 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
216 // SAFETY: the caller must ensure that the `new_size` does not overflow.
217 // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
218 let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
219 // SAFETY: the caller must ensure that `new_layout` is greater than zero.
220 let new_ptr = unsafe { self.alloc(new_layout) };
221 if !new_ptr.is_null() {
222 // SAFETY: the previously allocated block cannot overlap the newly allocated block.
223 // The safety contract for `dealloc` must be upheld by the caller.
225 ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
226 self.dealloc(ptr, layout);