Skip to content

Commit f6b0f47

Browse files
Rollup merge of #106045 - RalfJung:oom-nounwind-panic, r=Amanieu
default OOM handler: use non-unwinding panic, to match std handler The OOM handler in std will by default abort. This adjusts the default in liballoc to do the same, using the `can_unwind` flag on the panic info to indicate a non-unwinding panic. In practice this probably makes little difference since the liballoc default will only come into play in no-std situations where people write a custom panic handler, which most likely will not implement unwinding. But still, this seems more consistent. Cc `@rust-lang/wg-allocators,` #66741
2 parents c56d8ed + 5974f6f commit f6b0f47

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

library/alloc/src/alloc.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,20 @@ pub mod __alloc_error_handler {
402402
// `#[alloc_error_handler]`.
403403
#[rustc_std_internal_symbol]
404404
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
405-
panic!("memory allocation of {size} bytes failed")
405+
extern "Rust" {
406+
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
407+
// Its value depends on the -Zoom={panic,abort} compiler option.
408+
static __rust_alloc_error_handler_should_panic: u8;
409+
}
410+
411+
#[allow(unused_unsafe)]
412+
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
413+
panic!("memory allocation of {size} bytes failed")
414+
} else {
415+
core::panicking::panic_nounwind_fmt(format_args!(
416+
"memory allocation of {size} bytes failed"
417+
))
418+
}
406419
}
407420
}
408421

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
#![feature(const_maybe_uninit_as_mut_ptr)]
111111
#![feature(const_refs_to_cell)]
112112
#![feature(core_intrinsics)]
113+
#![feature(core_panic)]
113114
#![feature(const_eval_select)]
114115
#![feature(const_pin)]
115116
#![feature(const_waker)]

library/core/src/panicking.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,17 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
6464
unsafe { panic_impl(&pi) }
6565
}
6666

67-
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
68-
/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
67+
/// Like `panic_fmt`, but for non-unwinding panics.
68+
///
69+
/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
6970
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
7071
#[cfg_attr(feature = "panic_immediate_abort", inline)]
71-
#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
72+
#[track_caller]
73+
// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
74+
// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
75+
// which causes a "panic in a function that cannot unwind".
7276
#[rustc_nounwind]
73-
pub fn panic_nounwind(msg: &'static str) -> ! {
77+
pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
7478
if cfg!(feature = "panic_immediate_abort") {
7579
super::intrinsics::abort()
7680
}
@@ -83,8 +87,6 @@ pub fn panic_nounwind(msg: &'static str) -> ! {
8387
}
8488

8589
// PanicInfo with the `can_unwind` flag set to false forces an abort.
86-
let pieces = [msg];
87-
let fmt = fmt::Arguments::new_v1(&pieces, &[]);
8890
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
8991

9092
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
@@ -112,6 +114,15 @@ pub const fn panic(expr: &'static str) -> ! {
112114
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
113115
}
114116

117+
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
118+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
119+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
120+
#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
121+
#[rustc_nounwind]
122+
pub fn panic_nounwind(expr: &'static str) -> ! {
123+
panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
124+
}
125+
115126
#[inline]
116127
#[track_caller]
117128
#[rustc_diagnostic_item = "panic_str"]

library/std/src/alloc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ fn default_alloc_error_hook(layout: Layout) {
338338

339339
#[allow(unused_unsafe)]
340340
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
341-
panic!("memory allocation of {} bytes failed\n", layout.size());
341+
panic!("memory allocation of {} bytes failed", layout.size());
342342
} else {
343343
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
344344
}

0 commit comments

Comments
 (0)