]> git.lizzy.rs Git - rust.git/blob - library/core/src/alloc/mod.rs
Rollup merge of #101800 - chriss0612:feat/const_split_at_mut, r=fee1-dead
[rust.git] / library / core / src / alloc / mod.rs
1 //! Memory allocation APIs
2
3 #![stable(feature = "alloc_module", since = "1.28.0")]
4
5 mod global;
6 mod layout;
7
8 #[stable(feature = "global_alloc", since = "1.28.0")]
9 pub use self::global::GlobalAlloc;
10 #[stable(feature = "alloc_layout", since = "1.28.0")]
11 pub 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)]
19 pub use self::layout::LayoutErr;
20
21 #[stable(feature = "alloc_layout_error", since = "1.50.0")]
22 pub use self::layout::LayoutError;
23
24 #[cfg(not(bootstrap))]
25 use crate::error::Error;
26 use crate::fmt;
27 use crate::ptr::{self, NonNull};
28
29 /// The `AllocError` error indicates an allocation failure
30 /// that may be due to resource exhaustion or to
31 /// something wrong when combining the given input arguments with this
32 /// allocator.
33 #[unstable(feature = "allocator_api", issue = "32838")]
34 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
35 pub struct AllocError;
36
37 #[cfg(not(bootstrap))]
38 #[unstable(
39     feature = "allocator_api",
40     reason = "the precise API and guarantees it provides may be tweaked.",
41     issue = "32838"
42 )]
43 impl Error for AllocError {}
44
45 // (we need this for downstream impl of trait Error)
46 #[unstable(feature = "allocator_api", issue = "32838")]
47 impl fmt::Display for AllocError {
48     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49         f.write_str("memory allocation failed")
50     }
51 }
52
53 /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
54 /// data described via [`Layout`][].
55 ///
56 /// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having
57 /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
58 /// allocated memory.
59 ///
60 /// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying
61 /// allocator does not support this (like jemalloc) or return a null pointer (such as
62 /// `libc::malloc`), this must be caught by the implementation.
63 ///
64 /// ### Currently allocated memory
65 ///
66 /// Some of the methods require that a memory block be *currently allocated* via an allocator. This
67 /// means that:
68 ///
69 /// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or
70 ///   [`shrink`], and
71 ///
72 /// * the memory block has not been subsequently deallocated, where blocks are either deallocated
73 ///   directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or
74 ///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
75 ///   remains valid.
76 ///
77 /// [`allocate`]: Allocator::allocate
78 /// [`grow`]: Allocator::grow
79 /// [`shrink`]: Allocator::shrink
80 /// [`deallocate`]: Allocator::deallocate
81 ///
82 /// ### Memory fitting
83 ///
84 /// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
85 /// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
86 /// following conditions must hold:
87 ///
88 /// * The block must be allocated with the same alignment as [`layout.align()`], and
89 ///
90 /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
91 ///   - `min` is the size of the layout most recently used to allocate the block, and
92 ///   - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`].
93 ///
94 /// [`layout.align()`]: Layout::align
95 /// [`layout.size()`]: Layout::size
96 ///
97 /// # Safety
98 ///
99 /// * Memory blocks returned from an allocator must point to valid memory and retain their validity
100 ///   until the instance and all of its clones are dropped,
101 ///
102 /// * cloning or moving the allocator must not invalidate memory blocks returned from this
103 ///   allocator. A cloned allocator must behave like the same allocator, and
104 ///
105 /// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
106 ///   method of the allocator.
107 ///
108 /// [*currently allocated*]: #currently-allocated-memory
109 #[unstable(feature = "allocator_api", issue = "32838")]
110 #[const_trait]
111 pub unsafe trait Allocator {
112     /// Attempts to allocate a block of memory.
113     ///
114     /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
115     ///
116     /// The returned block may have a larger size than specified by `layout.size()`, and may or may
117     /// not have its contents initialized.
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. The memory may or may not have been freed, and should be
175     /// considered unusable.
176     ///
177     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
178     /// this allocator, and the contents of the memory block are unaltered.
179     ///
180     /// # Safety
181     ///
182     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
183     /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
184     /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
185     ///
186     /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
187     ///
188     /// [*currently allocated*]: #currently-allocated-memory
189     /// [*fit*]: #memory-fitting
190     ///
191     /// # Errors
192     ///
193     /// Returns `Err` if the new layout does not meet the allocator's size and alignment
194     /// constraints of the allocator, or if growing otherwise fails.
195     ///
196     /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
197     /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
198     /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
199     ///
200     /// Clients wishing to abort computation in response to an allocation error are encouraged to
201     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
202     ///
203     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
204     unsafe fn grow(
205         &self,
206         ptr: NonNull<u8>,
207         old_layout: Layout,
208         new_layout: Layout,
209     ) -> Result<NonNull<[u8]>, AllocError> {
210         debug_assert!(
211             new_layout.size() >= old_layout.size(),
212             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
213         );
214
215         let new_ptr = self.allocate(new_layout)?;
216
217         // SAFETY: because `new_layout.size()` must be greater than or equal to
218         // `old_layout.size()`, both the old and new memory allocation are valid for reads and
219         // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
220         // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
221         // safe. The safety contract for `dealloc` must be upheld by the caller.
222         unsafe {
223             ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
224             self.deallocate(ptr, old_layout);
225         }
226
227         Ok(new_ptr)
228     }
229
230     /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
231     /// returned.
232     ///
233     /// The memory block will contain the following contents after a successful call to
234     /// `grow_zeroed`:
235     ///   * Bytes `0..old_layout.size()` are preserved from the original allocation.
236     ///   * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
237     ///     the allocator implementation. `old_size` refers to the size of the memory block prior
238     ///     to the `grow_zeroed` call, which may be larger than the size that was originally
239     ///     requested when it was allocated.
240     ///   * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
241     ///     block returned by the `grow_zeroed` call.
242     ///
243     /// # Safety
244     ///
245     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
246     /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
247     /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
248     ///
249     /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
250     ///
251     /// [*currently allocated*]: #currently-allocated-memory
252     /// [*fit*]: #memory-fitting
253     ///
254     /// # Errors
255     ///
256     /// Returns `Err` if the new layout does not meet the allocator's size and alignment
257     /// constraints of the allocator, or if growing otherwise fails.
258     ///
259     /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
260     /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
261     /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
262     ///
263     /// Clients wishing to abort computation in response to an allocation error are encouraged to
264     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
265     ///
266     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
267     unsafe fn grow_zeroed(
268         &self,
269         ptr: NonNull<u8>,
270         old_layout: Layout,
271         new_layout: Layout,
272     ) -> Result<NonNull<[u8]>, AllocError> {
273         debug_assert!(
274             new_layout.size() >= old_layout.size(),
275             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
276         );
277
278         let new_ptr = self.allocate_zeroed(new_layout)?;
279
280         // SAFETY: because `new_layout.size()` must be greater than or equal to
281         // `old_layout.size()`, both the old and new memory allocation are valid for reads and
282         // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
283         // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
284         // safe. The safety contract for `dealloc` must be upheld by the caller.
285         unsafe {
286             ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size());
287             self.deallocate(ptr, old_layout);
288         }
289
290         Ok(new_ptr)
291     }
292
293     /// Attempts to shrink the memory block.
294     ///
295     /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
296     /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
297     /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
298     ///
299     /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
300     /// transferred to this allocator. The memory may or may not have been freed, and should be
301     /// considered unusable.
302     ///
303     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
304     /// this allocator, and the contents of the memory block are unaltered.
305     ///
306     /// # Safety
307     ///
308     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
309     /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
310     /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
311     ///
312     /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
313     ///
314     /// [*currently allocated*]: #currently-allocated-memory
315     /// [*fit*]: #memory-fitting
316     ///
317     /// # Errors
318     ///
319     /// Returns `Err` if the new layout does not meet the allocator's size and alignment
320     /// constraints of the allocator, or if shrinking otherwise fails.
321     ///
322     /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
323     /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
324     /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
325     ///
326     /// Clients wishing to abort computation in response to an allocation error are encouraged to
327     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
328     ///
329     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
330     unsafe fn shrink(
331         &self,
332         ptr: NonNull<u8>,
333         old_layout: Layout,
334         new_layout: Layout,
335     ) -> Result<NonNull<[u8]>, AllocError> {
336         debug_assert!(
337             new_layout.size() <= old_layout.size(),
338             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
339         );
340
341         let new_ptr = self.allocate(new_layout)?;
342
343         // SAFETY: because `new_layout.size()` must be lower than or equal to
344         // `old_layout.size()`, both the old and new memory allocation are valid for reads and
345         // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
346         // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
347         // safe. The safety contract for `dealloc` must be upheld by the caller.
348         unsafe {
349             ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size());
350             self.deallocate(ptr, old_layout);
351         }
352
353         Ok(new_ptr)
354     }
355
356     /// Creates a "by reference" adapter for this instance of `Allocator`.
357     ///
358     /// The returned adapter also implements `Allocator` and will simply borrow this.
359     #[inline(always)]
360     fn by_ref(&self) -> &Self
361     where
362         Self: Sized,
363     {
364         self
365     }
366 }
367
368 #[unstable(feature = "allocator_api", issue = "32838")]
369 unsafe impl<A> Allocator for &A
370 where
371     A: Allocator + ?Sized,
372 {
373     #[inline]
374     fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
375         (**self).allocate(layout)
376     }
377
378     #[inline]
379     fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
380         (**self).allocate_zeroed(layout)
381     }
382
383     #[inline]
384     unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
385         // SAFETY: the safety contract must be upheld by the caller
386         unsafe { (**self).deallocate(ptr, layout) }
387     }
388
389     #[inline]
390     unsafe fn grow(
391         &self,
392         ptr: NonNull<u8>,
393         old_layout: Layout,
394         new_layout: Layout,
395     ) -> Result<NonNull<[u8]>, AllocError> {
396         // SAFETY: the safety contract must be upheld by the caller
397         unsafe { (**self).grow(ptr, old_layout, new_layout) }
398     }
399
400     #[inline]
401     unsafe fn grow_zeroed(
402         &self,
403         ptr: NonNull<u8>,
404         old_layout: Layout,
405         new_layout: Layout,
406     ) -> Result<NonNull<[u8]>, AllocError> {
407         // SAFETY: the safety contract must be upheld by the caller
408         unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
409     }
410
411     #[inline]
412     unsafe fn shrink(
413         &self,
414         ptr: NonNull<u8>,
415         old_layout: Layout,
416         new_layout: Layout,
417     ) -> Result<NonNull<[u8]>, AllocError> {
418         // SAFETY: the safety contract must be upheld by the caller
419         unsafe { (**self).shrink(ptr, old_layout, new_layout) }
420     }
421 }