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