diff options
Diffstat (limited to 'library/std')
| -rw-r--r-- | library/std/src/alloc.rs | 73 | ||||
| -rw-r--r-- | library/std/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/std/src/prelude/v1.rs | 4 |
3 files changed, 76 insertions, 2 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 448a8edc291..c5a5991cc81 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -57,8 +57,9 @@ #![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics; -use core::ptr; use core::ptr::NonNull; +use core::sync::atomic::{AtomicPtr, Ordering}; +use core::{mem, ptr}; #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] @@ -285,6 +286,76 @@ unsafe impl Allocator for System { } } +static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); + +/// Registers a custom allocation error hook, replacing any that was previously registered. +/// +/// The allocation error hook is invoked when an infallible memory allocation fails, before +/// the runtime aborts. The default hook prints a message to standard error, +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. +/// +/// The hook is provided with a `Layout` struct which contains information +/// about the allocation that failed. +/// +/// The allocation error hook is a global resource. +/// +/// # Examples +/// +/// ``` +/// #![feature(alloc_error_hook)] +/// +/// use std::alloc::{Layout, set_alloc_error_hook}; +/// +/// fn custom_alloc_error_hook(layout: Layout) { +/// panic!("memory allocation of {} bytes failed", layout.size()); +/// } +/// +/// set_alloc_error_hook(custom_alloc_error_hook); +/// ``` +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { + HOOK.store(hook as *mut (), Ordering::SeqCst); +} + +/// Unregisters the current allocation error hook, returning it. +/// +/// *See also the function [`set_alloc_error_hook`].* +/// +/// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { + let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } +} + +fn default_alloc_error_hook(layout: Layout) { + extern "Rust" { + // This symbol is emitted by rustc next to __rust_alloc_error_handler. + // Its value depends on the -Zoom={panic,abort} compiler option. + static __rust_alloc_error_handler_should_panic: u8; + } + + #[allow(unused_unsafe)] + if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + panic!("memory allocation of {} bytes failed", layout.size()); + } else { + rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); + } +} + +#[cfg(not(test))] +#[doc(hidden)] +#[alloc_error_handler] +#[unstable(feature = "alloc_internals", issue = "none")] +pub fn rust_oom(layout: Layout) -> ! { + let hook = HOOK.load(Ordering::SeqCst); + let hook: fn(Layout) = + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; + hook(layout); + crate::process::abort() +} + #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 933f75d638b..31400aa1820 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -236,6 +236,7 @@ // // Language features: // tidy-alphabetical-start +#![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4f325a70b18..2aefd7c513d 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -60,7 +60,9 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case}; +pub use core::prelude::v1::{ + alloc_error_handler, bench, derive, global_allocator, test, test_case, +}; #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; |
