1 //! Memory allocation APIs
3 #![stable(feature = "alloc_module", since = "1.28.0")]
7 use core::intrinsics::{min_align_of_val, size_of_val};
11 use core::ptr::{self, NonNull};
13 #[stable(feature = "alloc_module", since = "1.28.0")]
15 pub use core::alloc::*;
21 // These are the magic symbols to call the global allocator. rustc generates
22 // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
23 // (the code expanding that attribute macro generates those functions), or to call
24 // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
27 #[rustc_allocator_nounwind]
28 fn __rust_alloc(size: usize, align: usize) -> *mut u8;
29 #[rustc_allocator_nounwind]
30 fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
31 #[rustc_allocator_nounwind]
32 fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
33 #[rustc_allocator_nounwind]
34 fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
37 /// The global memory allocator.
39 /// This type implements the [`AllocRef`] trait by forwarding calls
40 /// to the allocator registered with the `#[global_allocator]` attribute
41 /// if there is one, or the `std` crate’s default.
43 /// Note: while this type is unstable, the functionality it provides can be
44 /// accessed through the [free functions in `alloc`](self#functions).
45 #[unstable(feature = "allocator_api", issue = "32838")]
46 #[derive(Copy, Clone, Default, Debug)]
51 pub use std::alloc::Global;
53 /// Allocate memory with the global allocator.
55 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
56 /// of the allocator registered with the `#[global_allocator]` attribute
57 /// if there is one, or the `std` crate’s default.
59 /// This function is expected to be deprecated in favor of the `alloc` method
60 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
64 /// See [`GlobalAlloc::alloc`].
69 /// use std::alloc::{alloc, dealloc, Layout};
72 /// let layout = Layout::new::<u16>();
73 /// let ptr = alloc(layout);
75 /// *(ptr as *mut u16) = 42;
76 /// assert_eq!(*(ptr as *mut u16), 42);
78 /// dealloc(ptr, layout);
81 #[stable(feature = "global_alloc", since = "1.28.0")]
83 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
84 unsafe { __rust_alloc(layout.size(), layout.align()) }
87 /// Deallocate memory with the global allocator.
89 /// This function forwards calls to the [`GlobalAlloc::dealloc`] method
90 /// of the allocator registered with the `#[global_allocator]` attribute
91 /// if there is one, or the `std` crate’s default.
93 /// This function is expected to be deprecated in favor of the `dealloc` method
94 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
98 /// See [`GlobalAlloc::dealloc`].
99 #[stable(feature = "global_alloc", since = "1.28.0")]
101 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
102 unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
105 /// Reallocate memory with the global allocator.
107 /// This function forwards calls to the [`GlobalAlloc::realloc`] method
108 /// of the allocator registered with the `#[global_allocator]` attribute
109 /// if there is one, or the `std` crate’s default.
111 /// This function is expected to be deprecated in favor of the `realloc` method
112 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
116 /// See [`GlobalAlloc::realloc`].
117 #[stable(feature = "global_alloc", since = "1.28.0")]
119 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
120 unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
123 /// Allocate zero-initialized memory with the global allocator.
125 /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
126 /// of the allocator registered with the `#[global_allocator]` attribute
127 /// if there is one, or the `std` crate’s default.
129 /// This function is expected to be deprecated in favor of the `alloc_zeroed` method
130 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
134 /// See [`GlobalAlloc::alloc_zeroed`].
139 /// use std::alloc::{alloc_zeroed, dealloc, Layout};
142 /// let layout = Layout::new::<u16>();
143 /// let ptr = alloc_zeroed(layout);
145 /// assert_eq!(*(ptr as *mut u16), 0);
147 /// dealloc(ptr, layout);
150 #[stable(feature = "global_alloc", since = "1.28.0")]
152 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
153 unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
159 fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
160 match layout.size() {
161 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
162 // SAFETY: `layout` is non-zero in size,
164 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
165 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
166 Ok(NonNull::slice_from_raw_parts(ptr, size))
171 // SAFETY: Same as `AllocRef::grow`
179 ) -> Result<NonNull<[u8]>, AllocError> {
181 new_layout.size() >= old_layout.size(),
182 "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
185 match old_layout.size() {
186 0 => self.alloc_impl(new_layout, zeroed),
188 // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
189 // as required by safety conditions. Other conditions must be upheld by the caller
190 old_size if old_layout.align() == new_layout.align() => unsafe {
191 let new_size = new_layout.size();
193 // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
194 intrinsics::assume(new_size >= old_layout.size());
196 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
197 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
199 raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
201 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
204 // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
205 // both the old and new memory allocation are valid for reads and writes for `old_size`
206 // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
207 // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
208 // for `dealloc` must be upheld by the caller.
210 let new_ptr = self.alloc_impl(new_layout, zeroed)?;
211 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size);
212 self.dealloc(ptr, old_layout);
219 #[unstable(feature = "allocator_api", issue = "32838")]
221 unsafe impl AllocRef for Global {
223 fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
224 self.alloc_impl(layout, false)
228 fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
229 self.alloc_impl(layout, true)
233 unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
234 if layout.size() != 0 {
235 // SAFETY: `layout` is non-zero in size,
236 // other conditions must be upheld by the caller
237 unsafe { dealloc(ptr.as_ptr(), layout) }
247 ) -> Result<NonNull<[u8]>, AllocError> {
248 // SAFETY: all conditions must be upheld by the caller
249 unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
253 unsafe fn grow_zeroed(
258 ) -> Result<NonNull<[u8]>, AllocError> {
259 // SAFETY: all conditions must be upheld by the caller
260 unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
269 ) -> Result<NonNull<[u8]>, AllocError> {
271 new_layout.size() <= old_layout.size(),
272 "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
275 match new_layout.size() {
276 // SAFETY: conditions must be upheld by the caller
278 self.dealloc(ptr, old_layout);
279 Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
282 // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
283 new_size if old_layout.align() == new_layout.align() => unsafe {
284 // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
285 intrinsics::assume(new_size <= old_layout.size());
287 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
288 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
289 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
292 // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
293 // both the old and new memory allocation are valid for reads and writes for `new_size`
294 // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
295 // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
296 // for `dealloc` must be upheld by the caller.
298 let new_ptr = self.alloc(new_layout)?;
299 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size);
300 self.dealloc(ptr, old_layout);
307 /// The allocator for unique pointers.
308 // This function must not unwind. If it does, MIR codegen will fail.
310 #[lang = "exchange_malloc"]
312 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
313 let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
314 match Global.alloc(layout) {
315 Ok(ptr) => ptr.as_mut_ptr(),
316 Err(_) => handle_alloc_error(layout),
320 #[cfg_attr(not(test), lang = "box_free")]
322 // This signature has to be the same as `Box`, otherwise an ICE will happen.
323 // When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as
325 // For example if `Box` is changed to `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
326 // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
327 pub(crate) unsafe fn box_free<T: ?Sized, A: AllocRef>(ptr: Unique<T>, alloc: A) {
329 let size = size_of_val(ptr.as_ref());
330 let align = min_align_of_val(ptr.as_ref());
331 let layout = Layout::from_size_align_unchecked(size, align);
332 alloc.dealloc(ptr.cast().into(), layout)
336 // # Allocation error handler
339 // This is the magic symbol to call the global alloc error handler. rustc generates
340 // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
341 // default implementations below (`__rdl_oom`) otherwise.
342 #[rustc_allocator_nounwind]
343 fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
346 /// Abort on memory allocation error or failure.
348 /// Callers of memory allocation APIs wishing to abort computation
349 /// in response to an allocation error are encouraged to call this function,
350 /// rather than directly invoking `panic!` or similar.
352 /// The default behavior of this function is to print a message to standard error
353 /// and abort the process.
354 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
356 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
357 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
358 #[stable(feature = "global_alloc", since = "1.28.0")]
359 #[cfg(not(any(test, bootstrap)))]
360 #[rustc_allocator_nounwind]
361 pub fn handle_alloc_error(layout: Layout) -> ! {
363 __rust_alloc_error_handler(layout.size(), layout.align());
367 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
369 pub use std::alloc::handle_alloc_error;
371 // In stage0 (bootstrap) `__rust_alloc_error_handler`,
372 // might not be generated yet, because an old compiler is used,
373 // so use the old direct call.
374 #[cfg(all(bootstrap, not(test)))]
375 #[stable(feature = "global_alloc", since = "1.28.0")]
377 #[rustc_allocator_nounwind]
378 pub fn handle_alloc_error(layout: Layout) -> ! {
381 fn oom_impl(layout: Layout) -> !;
383 unsafe { oom_impl(layout) }
386 #[cfg(not(any(target_os = "hermit", test, bootstrap)))]
388 #[allow(unused_attributes)]
389 #[unstable(feature = "alloc_internals", issue = "none")]
390 pub mod __alloc_error_handler {
391 use crate::alloc::Layout;
393 // called via generated `__rust_alloc_error_handler`
395 // if there is no `#[alloc_error_handler]`
396 #[rustc_std_internal_symbol]
397 pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! {
398 panic!("memory allocation of {} bytes failed", size)
401 // if there is a `#[alloc_error_handler]`
402 #[rustc_std_internal_symbol]
403 pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! {
404 let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
407 fn oom_impl(layout: Layout) -> !;
409 unsafe { oom_impl(layout) }