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}