Skip to content

Commit 4cd1211

Browse files
authored
Rollup merge of #110782 - matthiaskrgr:revert_panic_oom, r=Amanieu
Revert panic oom This temporarily reverts rust-lang/rust#109507 until rust-lang/rust#110771 is addressed r? `@Amanieu`
2 parents 65545bb + d326fd9 commit 4cd1211

File tree

10 files changed

+124
-112
lines changed

10 files changed

+124
-112
lines changed

alloc/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,3 @@ compiler-builtins-mem = ['compiler_builtins/mem']
3535
compiler-builtins-c = ["compiler_builtins/c"]
3636
compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
3737
compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
38-
39-
# Make panics and failed asserts immediately abort without formatting any message
40-
panic_immediate_abort = ["core/panic_immediate_abort"]

alloc/src/alloc.rs

Lines changed: 17 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ use core::ptr::{self, NonNull};
1414
#[doc(inline)]
1515
pub 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-
2217
#[cfg(test)]
2318
mod tests;
2419

@@ -348,84 +343,28 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
348343
}
349344
}
350345

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-
}
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")]
374-
#[cfg(not(no_global_oom_handling))]
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-
386346
// # Allocation error handler
387347

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-
}
348+
#[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) -> !;
422354
}
423355

424356
/// Abort on memory allocation error or failure.
425357
///
426358
/// Callers of memory allocation APIs wishing to abort computation
427359
/// in response to an allocation error are encouraged to call this function,
428360
/// 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
429368
#[stable(feature = "global_alloc", since = "1.28.0")]
430369
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
431370
#[cfg(all(not(no_global_oom_handling), not(test)))]
@@ -436,7 +375,9 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
436375
}
437376

438377
fn rt_error(layout: Layout) -> ! {
439-
rust_oom(layout);
378+
unsafe {
379+
__rust_alloc_error_handler(layout.size(), layout.align());
380+
}
440381
}
441382

442383
unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
@@ -446,7 +387,6 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
446387
#[cfg(all(not(no_global_oom_handling), test))]
447388
pub use std::alloc::handle_alloc_error;
448389

449-
#[cfg(bootstrap)]
450390
#[cfg(all(not(no_global_oom_handling), not(test)))]
451391
#[doc(hidden)]
452392
#[allow(unused_attributes)]
@@ -458,7 +398,7 @@ pub mod __alloc_error_handler {
458398
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
459399
extern "Rust" {
460400
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
461-
// Its value depends on the -Zoom={unwind,abort} compiler option.
401+
// Its value depends on the -Zoom={panic,abort} compiler option.
462402
static __rust_alloc_error_handler_should_panic: u8;
463403
}
464404

alloc/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@
135135
#![feature(maybe_uninit_slice)]
136136
#![feature(maybe_uninit_uninit_array)]
137137
#![feature(maybe_uninit_uninit_array_transpose)]
138-
#![feature(panic_internals)]
139138
#![feature(pattern)]
140139
#![feature(pointer_byte_offsets)]
141140
#![feature(provide_any)]

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/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
6767
system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
6868

6969
# Make panics and failed asserts immediately abort without formatting any message
70-
panic_immediate_abort = ["alloc/panic_immediate_abort"]
70+
panic_immediate_abort = ["core/panic_immediate_abort"]
7171

7272
# Enable std_detect default features for stdarch/crates/std_detect:
7373
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml

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 & 1 deletion
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)]
@@ -319,7 +320,6 @@
319320
#![feature(get_mut_unchecked)]
320321
#![feature(map_try_insert)]
321322
#![feature(new_uninit)]
322-
#![feature(panic_oom_payload)]
323323
#![feature(slice_concat_trait)]
324324
#![feature(thin_box)]
325325
#![feature(try_reserve_kind)]

std/src/panicking.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -245,24 +245,19 @@ fn default_hook(info: &PanicInfo<'_>) {
245245

246246
// The current implementation always returns `Some`.
247247
let location = info.location().unwrap();
248+
249+
let msg = match info.payload().downcast_ref::<&'static str>() {
250+
Some(s) => *s,
251+
None => match info.payload().downcast_ref::<String>() {
252+
Some(s) => &s[..],
253+
None => "Box<dyn Any>",
254+
},
255+
};
248256
let thread = thread_info::current_thread();
249257
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
250258

251259
let write = |err: &mut dyn crate::io::Write| {
252-
// Use the panic message directly if available, otherwise take it from
253-
// the payload.
254-
if let Some(msg) = info.message() {
255-
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
256-
} else {
257-
let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() {
258-
*s
259-
} else if let Some(s) = info.payload().downcast_ref::<String>() {
260-
&s[..]
261-
} else {
262-
"Box<dyn Any>"
263-
};
264-
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
265-
}
260+
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
266261

267262
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
268263

@@ -529,8 +524,6 @@ pub fn panicking() -> bool {
529524
#[cfg(not(test))]
530525
#[panic_handler]
531526
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
532-
use alloc::alloc::AllocErrorPanicPayload;
533-
534527
struct PanicPayload<'a> {
535528
inner: &'a fmt::Arguments<'a>,
536529
string: Option<String>,
@@ -557,7 +550,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
557550
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
558551
fn take_box(&mut self) -> *mut (dyn Any + Send) {
559552
// We do two allocations here, unfortunately. But (a) they're required with the current
560-
// scheme, and (b) OOM uses its own separate payload type which doesn't allocate.
553+
// scheme, and (b) we don't handle panic + OOM properly anyway (see comment in
554+
// begin_panic below).
561555
let contents = mem::take(self.fill());
562556
Box::into_raw(Box::new(contents))
563557
}
@@ -582,14 +576,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
582576
let loc = info.location().unwrap(); // The current implementation always returns Some
583577
let msg = info.message().unwrap(); // The current implementation always returns Some
584578
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
585-
if let Some(payload) = info.payload().downcast_ref::<AllocErrorPanicPayload>() {
586-
rust_panic_with_hook(
587-
&mut payload.internal_clone(),
588-
info.message(),
589-
loc,
590-
info.can_unwind(),
591-
);
592-
} else if let Some(msg) = msg.as_str() {
579+
if let Some(msg) = msg.as_str() {
593580
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
594581
} else {
595582
rust_panic_with_hook(
@@ -636,7 +623,11 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
636623

637624
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
638625
fn take_box(&mut self) -> *mut (dyn Any + Send) {
639-
// Note that this should be the only allocation performed in this code path.
626+
// Note that this should be the only allocation performed in this code path. Currently
627+
// this means that panic!() on OOM will invoke this code path, but then again we're not
628+
// really ready for panic on OOM anyway. If we do start doing this, then we should
629+
// propagate this allocation to be performed in the parent of this thread instead of the
630+
// thread that's panicking.
640631
let data = match self.inner.take() {
641632
Some(a) => Box::new(a) as Box<dyn Any + Send>,
642633
None => process::abort(),

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)