at v6.5-rc6 16 kB view raw
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))] 8use core::intrinsics; 9use core::intrinsics::{min_align_of_val, size_of_val}; 10 11use core::ptr::Unique; 12#[cfg(not(test))] 13use core::ptr::{self, NonNull}; 14 15#[stable(feature = "alloc_module", since = "1.28.0")] 16#[doc(inline)] 17pub use core::alloc::*; 18 19use core::marker::Destruct; 20 21#[cfg(test)] 22mod tests; 23 24extern "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))] 57pub struct Global; 58 59#[cfg(test)] 60pub 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] 96pub 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] 114pub 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] 133pub 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] 167pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { 168 unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } 169} 170 171#[cfg(not(test))] 172impl 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))] 236unsafe 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] 326unsafe 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. 342pub(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))] 357extern "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] 380pub 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))] 396pub 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")] 402pub 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`. 426pub(crate) trait WriteCloneIntoRaw: Sized { 427 unsafe fn write_clone_into_raw(&self, target: *mut Self); 428} 429 430impl<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 439impl<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}