@@ -14,6 +14,11 @@ use core::ptr::{self, NonNull};
1414#[ doc( inline) ]
1515pub use core:: alloc:: * ;
1616
17+ #[ cfg( not( no_global_oom_handling) ) ]
18+ use core:: any:: Any ;
19+ #[ cfg( not( no_global_oom_handling) ) ]
20+ use core:: panic:: BoxMeUp ;
21+
1722#[ cfg( test) ]
1823mod tests;
1924
@@ -343,28 +348,84 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
343348 }
344349}
345350
346- // # Allocation error handler
351+ /// Payload passed to the panic handler when `handle_alloc_error` is called.
352+ #[ unstable( feature = "panic_oom_payload" , issue = "none" ) ]
353+ #[ derive( Debug ) ]
354+ pub struct AllocErrorPanicPayload {
355+ layout : Layout ,
356+ }
357+
358+ impl AllocErrorPanicPayload {
359+ /// Internal function for the standard library to clone a payload.
360+ #[ unstable( feature = "std_internals" , issue = "none" ) ]
361+ #[ doc( hidden) ]
362+ pub fn internal_clone ( & self ) -> Self {
363+ AllocErrorPanicPayload { layout : self . layout }
364+ }
347365
366+ /// Returns the [`Layout`] of the allocation attempt that caused the error.
367+ #[ unstable( feature = "panic_oom_payload" , issue = "none" ) ]
368+ pub fn layout ( & self ) -> Layout {
369+ self . layout
370+ }
371+ }
372+
373+ #[ unstable( feature = "std_internals" , issue = "none" ) ]
348374#[ cfg( not( no_global_oom_handling) ) ]
349- extern "Rust" {
350- // This is the magic symbol to call the global alloc error handler. rustc generates
351- // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
352- // default implementations below (`__rdl_oom`) otherwise.
353- fn __rust_alloc_error_handler ( size : usize , align : usize ) -> !;
375+ unsafe impl BoxMeUp for AllocErrorPanicPayload {
376+ fn take_box ( & mut self ) -> * mut ( dyn Any + Send ) {
377+ use crate :: boxed:: Box ;
378+ Box :: into_raw ( Box :: new ( self . internal_clone ( ) ) )
379+ }
380+
381+ fn get ( & mut self ) -> & ( dyn Any + Send ) {
382+ self
383+ }
384+ }
385+
386+ // # Allocation error handler
387+
388+ #[ cfg( all( not( no_global_oom_handling) , not( test) ) ) ]
389+ fn rust_oom ( layout : Layout ) -> ! {
390+ if cfg ! ( feature = "panic_immediate_abort" ) {
391+ core:: intrinsics:: abort ( )
392+ }
393+
394+ extern "Rust" {
395+ // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
396+ // that gets resolved to the `#[panic_handler]` function.
397+ #[ lang = "panic_impl" ]
398+ fn panic_impl ( pi : & core:: panic:: PanicInfo < ' _ > ) -> !;
399+
400+ // This symbol is emitted by rustc .
401+ // Its value depends on the -Zoom={unwind,abort} compiler option.
402+ static __rust_alloc_error_handler_should_panic: u8 ;
403+ }
404+
405+ // Hack to work around issues with the lifetime of Arguments.
406+ match format_args ! ( "memory allocation of {} bytes failed" , layout. size( ) ) {
407+ fmt => {
408+ // Create a PanicInfo with a custom payload for the panic handler.
409+ let can_unwind = unsafe { __rust_alloc_error_handler_should_panic != 0 } ;
410+ let mut pi = core:: panic:: PanicInfo :: internal_constructor (
411+ Some ( & fmt) ,
412+ core:: panic:: Location :: caller ( ) ,
413+ can_unwind,
414+ ) ;
415+ let payload = AllocErrorPanicPayload { layout } ;
416+ pi. set_payload ( & payload) ;
417+
418+ // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
419+ unsafe { panic_impl ( & pi) }
420+ }
421+ }
354422}
355423
356424/// Abort on memory allocation error or failure.
357425///
358426/// Callers of memory allocation APIs wishing to abort computation
359427/// in response to an allocation error are encouraged to call this function,
360428/// rather than directly invoking `panic!` or similar.
361- ///
362- /// The default behavior of this function is to print a message to standard error
363- /// and abort the process.
364- /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
365- ///
366- /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
367- /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
368429#[ stable( feature = "global_alloc" , since = "1.28.0" ) ]
369430#[ rustc_const_unstable( feature = "const_alloc_error" , issue = "92523" ) ]
370431#[ cfg( all( not( no_global_oom_handling) , not( test) ) ) ]
@@ -375,9 +436,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
375436 }
376437
377438 fn rt_error ( layout : Layout ) -> ! {
378- unsafe {
379- __rust_alloc_error_handler ( layout. size ( ) , layout. align ( ) ) ;
380- }
439+ rust_oom ( layout) ;
381440 }
382441
383442 unsafe { core:: intrinsics:: const_eval_select ( ( layout, ) , ct_error, rt_error) }
@@ -387,6 +446,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
387446#[ cfg( all( not( no_global_oom_handling) , test) ) ]
388447pub use std:: alloc:: handle_alloc_error;
389448
449+ #[ cfg( bootstrap) ]
390450#[ cfg( all( not( no_global_oom_handling) , not( test) ) ) ]
391451#[ doc( hidden) ]
392452#[ allow( unused_attributes) ]
@@ -398,7 +458,7 @@ pub mod __alloc_error_handler {
398458 pub unsafe fn __rdl_oom ( size : usize , _align : usize ) -> ! {
399459 extern "Rust" {
400460 // This symbol is emitted by rustc next to __rust_alloc_error_handler.
401- // Its value depends on the -Zoom={panic ,abort} compiler option.
461+ // Its value depends on the -Zoom={unwind ,abort} compiler option.
402462 static __rust_alloc_error_handler_should_panic: u8 ;
403463 }
404464
0 commit comments