]>
Commit | Line | Data |
---|---|---|
ba9703b0 XL |
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")] | |
f9f354fc | 21 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
ba9703b0 XL |
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 | ||
ba9703b0 XL |
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 | /// | |
3dfed10e XL |
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.) | |
ba9703b0 | 107 | /// |
3dfed10e XL |
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. | |
ba9703b0 | 110 | /// |
3dfed10e XL |
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. | |
ba9703b0 XL |
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 | |
3dfed10e XL |
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 | } | |
ba9703b0 XL |
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 | /// | |
3dfed10e | 149 | /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated |
ba9703b0 XL |
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 | |
3dfed10e | 152 | /// allocation referenced by `ptr` to fit the new layout. |
ba9703b0 | 153 | /// |
3dfed10e XL |
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. | |
ba9703b0 XL |
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 | /// | |
3dfed10e | 162 | /// [`NonNull<[u8]>`]: NonNull |
ba9703b0 XL |
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.), | |
ba9703b0 XL |
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, | |
3dfed10e XL |
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 | } | |
ba9703b0 | 214 | |
3dfed10e XL |
215 | Ok(new_ptr) |
216 | } | |
ba9703b0 | 217 | |
3dfed10e XL |
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)?; | |
f035d41b | 271 | |
3dfed10e XL |
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); | |
ba9703b0 | 280 | } |
3dfed10e XL |
281 | |
282 | Ok(new_ptr) | |
ba9703b0 XL |
283 | } |
284 | ||
285 | /// Attempts to shrink the memory block. | |
286 | /// | |
3dfed10e | 287 | /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated |
ba9703b0 XL |
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 | |
3dfed10e | 290 | /// allocation referenced by `ptr` to fit the new layout. |
ba9703b0 XL |
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 | |
3dfed10e XL |
294 | /// considered unusable unless it was transferred back to the caller again via the return value |
295 | /// of this method. | |
ba9703b0 XL |
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 | /// | |
3dfed10e | 300 | /// [`NonNull<[u8]>`]: NonNull |
ba9703b0 XL |
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 | |
ba9703b0 XL |
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, | |
3dfed10e XL |
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 | ); | |
ba9703b0 | 335 | |
3dfed10e XL |
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)?; | |
f035d41b | 340 | |
3dfed10e XL |
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); | |
ba9703b0 | 349 | } |
3dfed10e XL |
350 | |
351 | Ok(new_ptr) | |
ba9703b0 | 352 | } |
f9f354fc XL |
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] | |
3dfed10e XL |
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) | |
f9f354fc XL |
376 | } |
377 | ||
378 | #[inline] | |
379 | unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { | |
f035d41b XL |
380 | // SAFETY: the safety contract must be upheld by the caller |
381 | unsafe { (**self).dealloc(ptr, layout) } | |
f9f354fc XL |
382 | } |
383 | ||
384 | #[inline] | |
385 | unsafe fn grow( | |
386 | &mut self, | |
387 | ptr: NonNull<u8>, | |
388 | layout: Layout, | |
389 | new_size: usize, | |
3dfed10e XL |
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> { | |
f035d41b | 402 | // SAFETY: the safety contract must be upheld by the caller |
3dfed10e | 403 | unsafe { (**self).grow_zeroed(ptr, layout, new_size) } |
f9f354fc XL |
404 | } |
405 | ||
406 | #[inline] | |
407 | unsafe fn shrink( | |
408 | &mut self, | |
409 | ptr: NonNull<u8>, | |
410 | layout: Layout, | |
411 | new_size: usize, | |
3dfed10e | 412 | ) -> Result<NonNull<[u8]>, AllocErr> { |
f035d41b | 413 | // SAFETY: the safety contract must be upheld by the caller |
3dfed10e | 414 | unsafe { (**self).shrink(ptr, layout, new_size) } |
f9f354fc | 415 | } |
ba9703b0 | 416 | } |