Skip to content

Commit e6fe2bf

Browse files
committed
Revert "Remove #[alloc_error_handler] from the compiler and library"
This reverts commit abc0660118cc95f47445fd33502a11dd448f5968.
1 parent 0afd6ec commit e6fe2bf

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

alloc/src/alloc.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ fn rust_oom(layout: Layout) -> ! {
397397
#[lang = "panic_impl"]
398398
fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !;
399399

400-
// This symbol is emitted by rustc .
400+
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
401401
// Its value depends on the -Zoom={panic,abort} compiler option.
402402
static __rust_alloc_error_handler_should_panic: u8;
403403
}
@@ -426,6 +426,13 @@ fn rust_oom(layout: Layout) -> ! {
426426
/// Callers of memory allocation APIs wishing to abort computation
427427
/// in response to an allocation error are encouraged to call this function,
428428
/// rather than directly invoking `panic!` or similar.
429+
///
430+
/// The default behavior of this function is to print a message to standard error
431+
/// and abort the process.
432+
/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
433+
///
434+
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
435+
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
429436
#[stable(feature = "global_alloc", since = "1.28.0")]
430437
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
431438
#[cfg(all(not(no_global_oom_handling), not(test)))]
@@ -446,7 +453,6 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
446453
#[cfg(all(not(no_global_oom_handling), test))]
447454
pub use std::alloc::handle_alloc_error;
448455

449-
#[cfg(bootstrap)]
450456
#[cfg(all(not(no_global_oom_handling), not(test)))]
451457
#[doc(hidden)]
452458
#[allow(unused_attributes)]

core/src/macros/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,6 +1531,16 @@ pub(crate) mod builtin {
15311531
/* compiler built-in */
15321532
}
15331533

1534+
/// Attribute macro applied to a function to register it as a handler for allocation failure.
1535+
///
1536+
/// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
1537+
#[unstable(feature = "alloc_error_handler", issue = "51540")]
1538+
#[allow_internal_unstable(rustc_attrs)]
1539+
#[rustc_builtin_macro]
1540+
pub macro alloc_error_handler($item:item) {
1541+
/* compiler built-in */
1542+
}
1543+
15341544
/// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
15351545
#[unstable(
15361546
feature = "cfg_accessible",

core/src/prelude/v1.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
7676
// Do not `doc(no_inline)` so that they become doc items on their own
7777
// (no public module for them to be re-exported from).
7878
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
79-
pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
79+
pub use crate::macros::builtin::{
80+
alloc_error_handler, bench, derive, global_allocator, test, test_case,
81+
};
8082

8183
#[unstable(feature = "derive_const", issue = "none")]
8284
pub use crate::macros::builtin::derive_const;

std/src/alloc.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@
5757
#![stable(feature = "alloc_module", since = "1.28.0")]
5858

5959
use core::intrinsics;
60-
use core::ptr;
6160
use core::ptr::NonNull;
61+
use core::sync::atomic::{AtomicPtr, Ordering};
62+
use core::{mem, ptr};
6263

6364
#[stable(feature = "alloc_module", since = "1.28.0")]
6465
#[doc(inline)]
@@ -285,6 +286,76 @@ unsafe impl Allocator for System {
285286
}
286287
}
287288

289+
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
290+
291+
/// Registers a custom allocation error hook, replacing any that was previously registered.
292+
///
293+
/// The allocation error hook is invoked when an infallible memory allocation fails, before
294+
/// the runtime aborts. The default hook prints a message to standard error,
295+
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
296+
/// [`take_alloc_error_hook`] functions.
297+
///
298+
/// The hook is provided with a `Layout` struct which contains information
299+
/// about the allocation that failed.
300+
///
301+
/// The allocation error hook is a global resource.
302+
///
303+
/// # Examples
304+
///
305+
/// ```
306+
/// #![feature(alloc_error_hook)]
307+
///
308+
/// use std::alloc::{Layout, set_alloc_error_hook};
309+
///
310+
/// fn custom_alloc_error_hook(layout: Layout) {
311+
/// panic!("memory allocation of {} bytes failed", layout.size());
312+
/// }
313+
///
314+
/// set_alloc_error_hook(custom_alloc_error_hook);
315+
/// ```
316+
#[unstable(feature = "alloc_error_hook", issue = "51245")]
317+
pub fn set_alloc_error_hook(hook: fn(Layout)) {
318+
HOOK.store(hook as *mut (), Ordering::SeqCst);
319+
}
320+
321+
/// Unregisters the current allocation error hook, returning it.
322+
///
323+
/// *See also the function [`set_alloc_error_hook`].*
324+
///
325+
/// If no custom hook is registered, the default hook will be returned.
326+
#[unstable(feature = "alloc_error_hook", issue = "51245")]
327+
pub fn take_alloc_error_hook() -> fn(Layout) {
328+
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
329+
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
330+
}
331+
332+
fn default_alloc_error_hook(layout: Layout) {
333+
extern "Rust" {
334+
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
335+
// Its value depends on the -Zoom={panic,abort} compiler option.
336+
static __rust_alloc_error_handler_should_panic: u8;
337+
}
338+
339+
#[allow(unused_unsafe)]
340+
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
341+
panic!("memory allocation of {} bytes failed", layout.size());
342+
} else {
343+
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
344+
}
345+
}
346+
347+
#[cfg(not(test))]
348+
#[doc(hidden)]
349+
#[alloc_error_handler]
350+
#[unstable(feature = "alloc_internals", issue = "none")]
351+
pub fn rust_oom(layout: Layout) -> ! {
352+
let hook = HOOK.load(Ordering::SeqCst);
353+
let hook: fn(Layout) =
354+
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
355+
hook(layout);
356+
crate::process::abort()
357+
}
358+
288359
#[cfg(not(test))]
289360
#[doc(hidden)]
290361
#[allow(unused_attributes)]

std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
//
237237
// Language features:
238238
// tidy-alphabetical-start
239+
#![feature(alloc_error_handler)]
239240
#![feature(allocator_internals)]
240241
#![feature(allow_internal_unsafe)]
241242
#![feature(allow_internal_unstable)]

std/src/prelude/v1.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
6060
// Do not `doc(no_inline)` so that they become doc items on their own
6161
// (no public module for them to be re-exported from).
6262
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
63-
pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
63+
pub use core::prelude::v1::{
64+
alloc_error_handler, bench, derive, global_allocator, test, test_case,
65+
};
6466

6567
#[unstable(feature = "derive_const", issue = "none")]
6668
pub use core::prelude::v1::derive_const;

0 commit comments

Comments
 (0)