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