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