1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 //! Memory allocation APIs 4 5 #![stable(feature = "alloc_module", since = "1.28.0")] 6 7 #[cfg(not(test))] 8 use core::intrinsics; 9 use core::intrinsics::{min_align_of_val, size_of_val}; 10 11 use core::ptr::Unique; 12 #[cfg(not(test))] 13 use core::ptr::{self, NonNull}; 14 15 #[stable(feature = "alloc_module", since = "1.28.0")] 16 #[doc(inline)] 17 pub use core::alloc::*; 18 19 use core::marker::Destruct; 20 21 #[cfg(test)] 22 mod tests; 23 24 extern "Rust" { 25 // These are the magic symbols to call the global allocator. rustc generates 26 // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute 27 // (the code expanding that attribute macro generates those functions), or to call 28 // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) 29 // otherwise. 30 // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them 31 // like `malloc`, `realloc`, and `free`, respectively. 32 #[rustc_allocator] 33 #[rustc_nounwind] 34 fn __rust_alloc(size: usize, align: usize) -> *mut u8; 35 #[rustc_deallocator] 36 #[rustc_nounwind] 37 fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); 38 #[rustc_reallocator] 39 #[rustc_nounwind] 40 fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; 41 #[rustc_allocator_zeroed] 42 #[rustc_nounwind] 43 fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; 44 } 45 46 /// The global memory allocator. 47 /// 48 /// This type implements the [`Allocator`] trait by forwarding calls 49 /// to the allocator registered with the `#[global_allocator]` attribute 50 /// if there is one, or the `std` crate’s default. 51 /// 52 /// Note: while this type is unstable, the functionality it provides can be 53 /// accessed through the [free functions in `alloc`](self#functions). 54 #[unstable(feature = "allocator_api", issue = "32838")] 55 #[derive(Copy, Clone, Default, Debug)] 56 #[cfg(not(test))] 57 pub struct Global; 58 59 #[cfg(test)] 60 pub use std::alloc::Global; 61 62 /// Allocate memory with the global allocator. 63 /// 64 /// This function forwards calls to the [`GlobalAlloc::alloc`] method 65 /// of the allocator registered with the `#[global_allocator]` attribute 66 /// if there is one, or the `std` crate’s default. 67 /// 68 /// This function is expected to be deprecated in favor of the `alloc` method 69 /// of the [`Global`] type when it and the [`Allocator`] trait become stable. 70 /// 71 /// # Safety 72 /// 73 /// See [`GlobalAlloc::alloc`]. 74 /// 75 /// # Examples 76 /// 77 /// ``` 78 /// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout}; 79 /// 80 /// unsafe { 81 /// let layout = Layout::new::<u16>(); 82 /// let ptr = alloc(layout); 83 /// if ptr.is_null() { 84 /// handle_alloc_error(layout); 85 /// } 86 /// 87 /// *(ptr as *mut u16) = 42; 88 /// assert_eq!(*(ptr as *mut u16), 42); 89 /// 90 /// dealloc(ptr, layout); 91 /// } 92 /// ``` 93 #[stable(feature = "global_alloc", since = "1.28.0")] 94 #[must_use = "losing the pointer will leak memory"] 95 #[inline] 96 pub unsafe fn alloc(layout: Layout) -> *mut u8 { 97 unsafe { __rust_alloc(layout.size(), layout.align()) } 98 } 99 100 /// Deallocate memory with the global allocator. 101 /// 102 /// This function forwards calls to the [`GlobalAlloc::dealloc`] method 103 /// of the allocator registered with the `#[global_allocator]` attribute 104 /// if there is one, or the `std` crate’s default. 105 /// 106 /// This function is expected to be deprecated in favor of the `dealloc` method 107 /// of the [`Global`] type when it and the [`Allocator`] trait become stable. 108 /// 109 /// # Safety 110 /// 111 /// See [`GlobalAlloc::dealloc`]. 112 #[stable(feature = "global_alloc", since = "1.28.0")] 113 #[inline] 114 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { 115 unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } 116 } 117 118 /// Reallocate memory with the global allocator. 119 /// 120 /// This function forwards calls to the [`GlobalAlloc::realloc`] method 121 /// of the allocator registered with the `#[global_allocator]` attribute 122 /// if there is one, or the `std` crate’s default. 123 /// 124 /// This function is expected to be deprecated in favor of the `realloc` method 125 /// of the [`Global`] type when it and the [`Allocator`] trait become stable. 126 /// 127 /// # Safety 128 /// 129 /// See [`GlobalAlloc::realloc`]. 130 #[stable(feature = "global_alloc", since = "1.28.0")] 131 #[must_use = "losing the pointer will leak memory"] 132 #[inline] 133 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 134 unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } 135 } 136 137 /// Allocate zero-initialized memory with the global allocator. 138 /// 139 /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method 140 /// of the allocator registered with the `#[global_allocator]` attribute 141 /// if there is one, or the `std` crate’s default. 142 /// 143 /// This function is expected to be deprecated in favor of the `alloc_zeroed` method 144 /// of the [`Global`] type when it and the [`Allocator`] trait become stable. 145 /// 146 /// # Safety 147 /// 148 /// See [`GlobalAlloc::alloc_zeroed`]. 149 /// 150 /// # Examples 151 /// 152 /// ``` 153 /// use std::alloc::{alloc_zeroed, dealloc, Layout}; 154 /// 155 /// unsafe { 156 /// let layout = Layout::new::<u16>(); 157 /// let ptr = alloc_zeroed(layout); 158 /// 159 /// assert_eq!(*(ptr as *mut u16), 0); 160 /// 161 /// dealloc(ptr, layout); 162 /// } 163 /// ``` 164 #[stable(feature = "global_alloc", since = "1.28.0")] 165 #[must_use = "losing the pointer will leak memory"] 166 #[inline] 167 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { 168 unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } 169 } 170 171 #[cfg(not(test))] 172 impl Global { 173 #[inline] 174 fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { 175 match layout.size() { 176 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), 177 // SAFETY: `layout` is non-zero in size, 178 size => unsafe { 179 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) }; 180 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; 181 Ok(NonNull::slice_from_raw_parts(ptr, size)) 182 }, 183 } 184 } 185 186 // SAFETY: Same as `Allocator::grow` 187 #[inline] 188 unsafe fn grow_impl( 189 &self, 190 ptr: NonNull<u8>, 191 old_layout: Layout, 192 new_layout: Layout, 193 zeroed: bool, 194 ) -> Result<NonNull<[u8]>, AllocError> { 195 debug_assert!( 196 new_layout.size() >= old_layout.size(), 197 "`new_layout.size()` must be greater than or equal to `old_layout.size()`" 198 ); 199 200 match old_layout.size() { 201 0 => self.alloc_impl(new_layout, zeroed), 202 203 // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` 204 // as required by safety conditions. Other conditions must be upheld by the caller 205 old_size if old_layout.align() == new_layout.align() => unsafe { 206 let new_size = new_layout.size(); 207 208 // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. 209 intrinsics::assume(new_size >= old_layout.size()); 210 211 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); 212 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; 213 if zeroed { 214 raw_ptr.add(old_size).write_bytes(0, new_size - old_size); 215 } 216 Ok(NonNull::slice_from_raw_parts(ptr, new_size)) 217 }, 218 219 // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, 220 // both the old and new memory allocation are valid for reads and writes for `old_size` 221 // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap 222 // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract 223 // for `dealloc` must be upheld by the caller. 224 old_size => unsafe { 225 let new_ptr = self.alloc_impl(new_layout, zeroed)?; 226 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); 227 self.deallocate(ptr, old_layout); 228 Ok(new_ptr) 229 }, 230 } 231 } 232 } 233 234 #[unstable(feature = "allocator_api", issue = "32838")] 235 #[cfg(not(test))] 236 unsafe impl Allocator for Global { 237 #[inline] 238 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 239 self.alloc_impl(layout, false) 240 } 241 242 #[inline] 243 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 244 self.alloc_impl(layout, true) 245 } 246 247 #[inline] 248 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { 249 if layout.size() != 0 { 250 // SAFETY: `layout` is non-zero in size, 251 // other conditions must be upheld by the caller 252 unsafe { dealloc(ptr.as_ptr(), layout) } 253 } 254 } 255 256 #[inline] 257 unsafe fn grow( 258 &self, 259 ptr: NonNull<u8>, 260 old_layout: Layout, 261 new_layout: Layout, 262 ) -> Result<NonNull<[u8]>, AllocError> { 263 // SAFETY: all conditions must be upheld by the caller 264 unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } 265 } 266 267 #[inline] 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 // SAFETY: all conditions must be upheld by the caller 275 unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } 276 } 277 278 #[inline] 279 unsafe fn shrink( 280 &self, 281 ptr: NonNull<u8>, 282 old_layout: Layout, 283 new_layout: Layout, 284 ) -> Result<NonNull<[u8]>, AllocError> { 285 debug_assert!( 286 new_layout.size() <= old_layout.size(), 287 "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" 288 ); 289 290 match new_layout.size() { 291 // SAFETY: conditions must be upheld by the caller 292 0 => unsafe { 293 self.deallocate(ptr, old_layout); 294 Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) 295 }, 296 297 // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller 298 new_size if old_layout.align() == new_layout.align() => unsafe { 299 // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. 300 intrinsics::assume(new_size <= old_layout.size()); 301 302 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); 303 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; 304 Ok(NonNull::slice_from_raw_parts(ptr, new_size)) 305 }, 306 307 // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, 308 // both the old and new memory allocation are valid for reads and writes for `new_size` 309 // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap 310 // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract 311 // for `dealloc` must be upheld by the caller. 312 new_size => unsafe { 313 let new_ptr = self.allocate(new_layout)?; 314 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); 315 self.deallocate(ptr, old_layout); 316 Ok(new_ptr) 317 }, 318 } 319 } 320 } 321 322 /// The allocator for unique pointers. 323 #[cfg(all(not(no_global_oom_handling), not(test)))] 324 #[lang = "exchange_malloc"] 325 #[inline] 326 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { 327 let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; 328 match Global.allocate(layout) { 329 Ok(ptr) => ptr.as_mut_ptr(), 330 Err(_) => handle_alloc_error(layout), 331 } 332 } 333 334 #[cfg_attr(not(test), lang = "box_free")] 335 #[inline] 336 #[rustc_const_unstable(feature = "const_box", issue = "92521")] 337 // This signature has to be the same as `Box`, otherwise an ICE will happen. 338 // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as 339 // well. 340 // For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`, 341 // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well. 342 pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Destruct>( 343 ptr: Unique<T>, 344 alloc: A, 345 ) { 346 unsafe { 347 let size = size_of_val(ptr.as_ref()); 348 let align = min_align_of_val(ptr.as_ref()); 349 let layout = Layout::from_size_align_unchecked(size, align); 350 alloc.deallocate(From::from(ptr.cast()), layout) 351 } 352 } 353 354 // # Allocation error handler 355 356 #[cfg(not(no_global_oom_handling))] 357 extern "Rust" { 358 // This is the magic symbol to call the global alloc error handler. rustc generates 359 // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the 360 // default implementations below (`__rdl_oom`) otherwise. 361 fn __rust_alloc_error_handler(size: usize, align: usize) -> !; 362 } 363 364 /// Abort on memory allocation error or failure. 365 /// 366 /// Callers of memory allocation APIs wishing to abort computation 367 /// in response to an allocation error are encouraged to call this function, 368 /// rather than directly invoking `panic!` or similar. 369 /// 370 /// The default behavior of this function is to print a message to standard error 371 /// and abort the process. 372 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. 373 /// 374 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html 375 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html 376 #[stable(feature = "global_alloc", since = "1.28.0")] 377 #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] 378 #[cfg(all(not(no_global_oom_handling), not(test)))] 379 #[cold] 380 pub const fn handle_alloc_error(layout: Layout) -> ! { 381 const fn ct_error(_: Layout) -> ! { 382 panic!("allocation failed"); 383 } 384 385 fn rt_error(layout: Layout) -> ! { 386 unsafe { 387 __rust_alloc_error_handler(layout.size(), layout.align()); 388 } 389 } 390 391 unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } 392 } 393 394 // For alloc test `std::alloc::handle_alloc_error` can be used directly. 395 #[cfg(all(not(no_global_oom_handling), test))] 396 pub use std::alloc::handle_alloc_error; 397 398 #[cfg(all(not(no_global_oom_handling), not(test)))] 399 #[doc(hidden)] 400 #[allow(unused_attributes)] 401 #[unstable(feature = "alloc_internals", issue = "none")] 402 pub mod __alloc_error_handler { 403 // called via generated `__rust_alloc_error_handler` if there is no 404 // `#[alloc_error_handler]`. 405 #[rustc_std_internal_symbol] 406 pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! { 407 extern "Rust" { 408 // This symbol is emitted by rustc next to __rust_alloc_error_handler. 409 // Its value depends on the -Zoom={panic,abort} compiler option. 410 static __rust_alloc_error_handler_should_panic: u8; 411 } 412 413 #[allow(unused_unsafe)] 414 if unsafe { __rust_alloc_error_handler_should_panic != 0 } { 415 panic!("memory allocation of {size} bytes failed") 416 } else { 417 core::panicking::panic_nounwind_fmt(format_args!( 418 "memory allocation of {size} bytes failed" 419 )) 420 } 421 } 422 } 423 424 /// Specialize clones into pre-allocated, uninitialized memory. 425 /// Used by `Box::clone` and `Rc`/`Arc::make_mut`. 426 pub(crate) trait WriteCloneIntoRaw: Sized { 427 unsafe fn write_clone_into_raw(&self, target: *mut Self); 428 } 429 430 impl<T: Clone> WriteCloneIntoRaw for T { 431 #[inline] 432 default unsafe fn write_clone_into_raw(&self, target: *mut Self) { 433 // Having allocated *first* may allow the optimizer to create 434 // the cloned value in-place, skipping the local and move. 435 unsafe { target.write(self.clone()) }; 436 } 437 } 438 439 impl<T: Copy> WriteCloneIntoRaw for T { 440 #[inline] 441 unsafe fn write_clone_into_raw(&self, target: *mut Self) { 442 // We can always copy in-place, without ever involving a local value. 443 unsafe { target.copy_from_nonoverlapping(self, 1) }; 444 } 445 } 446