@@ -14,6 +14,11 @@ use core::ptr::{self, NonNull};
14
14
#[ doc( inline) ]
15
15
pub use core:: alloc:: * ;
16
16
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
+
17
22
#[ cfg( test) ]
18
23
mod tests;
19
24
@@ -343,28 +348,84 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
343
348
}
344
349
}
345
350
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
+ }
347
365
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" ) ]
348
374
#[ 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
+ }
354
422
}
355
423
356
424
/// Abort on memory allocation error or failure.
357
425
///
358
426
/// Callers of memory allocation APIs wishing to abort computation
359
427
/// in response to an allocation error are encouraged to call this function,
360
428
/// 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
368
429
#[ stable( feature = "global_alloc" , since = "1.28.0" ) ]
369
430
#[ rustc_const_unstable( feature = "const_alloc_error" , issue = "92523" ) ]
370
431
#[ cfg( all( not( no_global_oom_handling) , not( test) ) ) ]
@@ -375,9 +436,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
375
436
}
376
437
377
438
fn rt_error ( layout : Layout ) -> ! {
378
- unsafe {
379
- __rust_alloc_error_handler ( layout. size ( ) , layout. align ( ) ) ;
380
- }
439
+ rust_oom ( layout) ;
381
440
}
382
441
383
442
unsafe { core:: intrinsics:: const_eval_select ( ( layout, ) , ct_error, rt_error) }
@@ -387,6 +446,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
387
446
#[ cfg( all( not( no_global_oom_handling) , test) ) ]
388
447
pub use std:: alloc:: handle_alloc_error;
389
448
449
+ #[ cfg( bootstrap) ]
390
450
#[ cfg( all( not( no_global_oom_handling) , not( test) ) ) ]
391
451
#[ doc( hidden) ]
392
452
#[ allow( unused_attributes) ]
@@ -398,7 +458,7 @@ pub mod __alloc_error_handler {
398
458
pub unsafe fn __rdl_oom ( size : usize , _align : usize ) -> ! {
399
459
extern "Rust" {
400
460
// 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.
402
462
static __rust_alloc_error_handler_should_panic: u8 ;
403
463
}
404
464
0 commit comments