Rollup merge of #66766 - RalfJung:panic-comments, r=SimonSapin
Panic machinery comments and tweaks This is mostly more comments, but I also renamed some things: * `BoxMeUp::box_me_up` is not terribly descriptive, and since this is a "take"-style method (the argument is `&mut self` but the return type is fully owned, even though you can't tell from the type) I chose a name involving "take". * `continue_panic_fmt` was very confusing as it was entirely unclear what was being continued -- for some time I thought "continue" might be the same as "resume" for a panic, but that's something entirely different. So I renamed this to `begin_panic_handler`, matching the `begin_panic*` theme of the other entry points. r? @Dylan-DPC @SimonSapin
This commit is contained in:
commit
56203be06f
5 changed files with 45 additions and 28 deletions
|
@ -266,6 +266,16 @@ impl fmt::Display for Location<'_> {
|
||||||
#[unstable(feature = "std_internals", issue = "0")]
|
#[unstable(feature = "std_internals", issue = "0")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub unsafe trait BoxMeUp {
|
pub unsafe trait BoxMeUp {
|
||||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send);
|
/// Take full ownership of the contents.
|
||||||
|
/// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
|
||||||
|
///
|
||||||
|
/// After this method got called, only some dummy default value is left in `self`.
|
||||||
|
/// Calling this method twice, or calling `get` after calling this method, is an error.
|
||||||
|
///
|
||||||
|
/// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
|
||||||
|
/// gets a borrowed `dyn BoxMeUp`.
|
||||||
|
fn take_box(&mut self) -> *mut (dyn Any + Send);
|
||||||
|
|
||||||
|
/// Just borrow the contents.
|
||||||
fn get(&mut self) -> &(dyn Any + Send);
|
fn get(&mut self) -> &(dyn Any + Send);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! This definition allows for panicking with any general message, but it does not
|
//! This definition allows for panicking with any general message, but it does not
|
||||||
//! allow for failing with a `Box<Any>` value. The reason for this is that libcore
|
//! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`,
|
||||||
//! is not allowed to allocate.
|
//! for which we fill in a dummy value in `PanicInfo::internal_constructor`.)
|
||||||
|
//! The reason for this is that libcore is not allowed to allocate.
|
||||||
//!
|
//!
|
||||||
//! This module contains a few other panicking functions, but these are just the
|
//! This module contains a few other panicking functions, but these are just the
|
||||||
//! necessary lang items for the compiler. All panics are funneled through this
|
//! necessary lang items for the compiler. All panics are funneled through this
|
||||||
//! one function. Currently, the actual symbol is declared in the standard
|
//! one function. The actual symbol is declared through the `#[panic_handler]` attribute.
|
||||||
//! library, but the location of this may change over time.
|
|
||||||
|
|
||||||
// ignore-tidy-undocumented-unsafe
|
// ignore-tidy-undocumented-unsafe
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||||
|
// that gets resolved to the `#[panic_handler]` function.
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
#[lang = "panic_impl"]
|
#[lang = "panic_impl"]
|
||||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||||
|
|
|
@ -94,5 +94,5 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
|
pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
|
||||||
let payload = payload as *mut &mut dyn BoxMeUp;
|
let payload = payload as *mut &mut dyn BoxMeUp;
|
||||||
imp::panic(Box::from_raw((*payload).box_me_up()))
|
imp::panic(Box::from_raw((*payload).take_box()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,5 +425,5 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "resume_unwind", since = "1.9.0")]
|
#[stable(feature = "resume_unwind", since = "1.9.0")]
|
||||||
pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
|
pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
|
||||||
panicking::update_count_then_panic(payload)
|
panicking::rust_panic_without_hook(payload)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use crate::sys_common::rwlock::RWLock;
|
||||||
use crate::sys_common::{thread_info, util};
|
use crate::sys_common::{thread_info, util};
|
||||||
use crate::sys_common::backtrace::{self, RustBacktrace};
|
use crate::sys_common::backtrace::{self, RustBacktrace};
|
||||||
use crate::thread;
|
use crate::thread;
|
||||||
|
use crate::process;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::io::set_panic;
|
use crate::io::set_panic;
|
||||||
|
@ -46,6 +47,8 @@ extern {
|
||||||
vtable_ptr: *mut usize) -> u32;
|
vtable_ptr: *mut usize) -> u32;
|
||||||
|
|
||||||
/// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
|
/// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
|
||||||
|
/// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend
|
||||||
|
/// on liballoc, and thus cannot use `Box`.
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
fn __rust_start_panic(payload: usize) -> u32;
|
fn __rust_start_panic(payload: usize) -> u32;
|
||||||
}
|
}
|
||||||
|
@ -296,14 +299,6 @@ pub fn panicking() -> bool {
|
||||||
update_panic_count(0) != 0
|
update_panic_count(0) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entry point of panic from the libcore crate (`panic_impl` lang item).
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[panic_handler]
|
|
||||||
#[unwind(allowed)]
|
|
||||||
pub fn rust_begin_panic(info: &PanicInfo<'_>) -> ! {
|
|
||||||
continue_panic_fmt(&info)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The entry point for panicking with a formatted message.
|
/// The entry point for panicking with a formatted message.
|
||||||
///
|
///
|
||||||
/// This is designed to reduce the amount of code required at the call
|
/// This is designed to reduce the amount of code required at the call
|
||||||
|
@ -324,13 +319,17 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
|
||||||
unsafe { intrinsics::abort() }
|
unsafe { intrinsics::abort() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just package everything into a `PanicInfo` and continue like libcore panics.
|
||||||
let (file, line, col) = *file_line_col;
|
let (file, line, col) = *file_line_col;
|
||||||
let location = Location::internal_constructor(file, line, col);
|
let location = Location::internal_constructor(file, line, col);
|
||||||
let info = PanicInfo::internal_constructor(Some(msg), &location);
|
let info = PanicInfo::internal_constructor(Some(msg), &location);
|
||||||
continue_panic_fmt(&info)
|
begin_panic_handler(&info)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
/// Entry point of panics from the libcore crate (`panic_impl` lang item).
|
||||||
|
#[cfg_attr(not(test), panic_handler)]
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||||
struct PanicPayload<'a> {
|
struct PanicPayload<'a> {
|
||||||
inner: &'a fmt::Arguments<'a>,
|
inner: &'a fmt::Arguments<'a>,
|
||||||
string: Option<String>,
|
string: Option<String>,
|
||||||
|
@ -345,6 +344,7 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||||
use crate::fmt::Write;
|
use crate::fmt::Write;
|
||||||
|
|
||||||
let inner = self.inner;
|
let inner = self.inner;
|
||||||
|
// Lazily, the first time this gets called, run the actual string formatting.
|
||||||
self.string.get_or_insert_with(|| {
|
self.string.get_or_insert_with(|| {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
drop(s.write_fmt(*inner));
|
drop(s.write_fmt(*inner));
|
||||||
|
@ -354,7 +354,7 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
|
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
|
||||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||||
let contents = mem::take(self.fill());
|
let contents = mem::take(self.fill());
|
||||||
Box::into_raw(Box::new(contents))
|
Box::into_raw(Box::new(contents))
|
||||||
}
|
}
|
||||||
|
@ -378,7 +378,9 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||||
&file_line_col);
|
&file_line_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is the entry point of panicking for panic!() and assert!().
|
/// This is the entry point of panicking for the non-format-string variants of
|
||||||
|
/// panic!() and assert!(). In particular, this is the only entry point that supports
|
||||||
|
/// arbitrary payloads, not just format strings.
|
||||||
#[unstable(feature = "libstd_sys_internals",
|
#[unstable(feature = "libstd_sys_internals",
|
||||||
reason = "used by the panic! macro",
|
reason = "used by the panic! macro",
|
||||||
issue = "0")]
|
issue = "0")]
|
||||||
|
@ -412,10 +414,10 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
|
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
|
||||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||||
let data = match self.inner.take() {
|
let data = match self.inner.take() {
|
||||||
Some(a) => Box::new(a) as Box<dyn Any + Send>,
|
Some(a) => Box::new(a) as Box<dyn Any + Send>,
|
||||||
None => Box::new(()),
|
None => process::abort(),
|
||||||
};
|
};
|
||||||
Box::into_raw(data)
|
Box::into_raw(data)
|
||||||
}
|
}
|
||||||
|
@ -423,7 +425,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
|
||||||
fn get(&mut self) -> &(dyn Any + Send) {
|
fn get(&mut self) -> &(dyn Any + Send) {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
Some(ref a) => a,
|
Some(ref a) => a,
|
||||||
None => &(),
|
None => process::abort(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,9 +459,12 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
|
||||||
let mut info = PanicInfo::internal_constructor(message, &location);
|
let mut info = PanicInfo::internal_constructor(message, &location);
|
||||||
HOOK_LOCK.read();
|
HOOK_LOCK.read();
|
||||||
match HOOK {
|
match HOOK {
|
||||||
// Some platforms know that printing to stderr won't ever actually
|
// Some platforms (like wasm) know that printing to stderr won't ever actually
|
||||||
// print anything, and if that's the case we can skip the default
|
// print anything, and if that's the case we can skip the default
|
||||||
// hook.
|
// hook. Since string formatting happens lazily when calling `payload`
|
||||||
|
// methods, this means we avoid formatting the string at all!
|
||||||
|
// (The panic runtime might still call `payload.take_box()` though and trigger
|
||||||
|
// formatting.)
|
||||||
Hook::Default if panic_output().is_none() => {}
|
Hook::Default if panic_output().is_none() => {}
|
||||||
Hook::Default => {
|
Hook::Default => {
|
||||||
info.set_payload(payload.get());
|
info.set_payload(payload.get());
|
||||||
|
@ -486,14 +491,15 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
|
||||||
rust_panic(payload)
|
rust_panic(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shim around rust_panic. Called by resume_unwind.
|
/// This is the entry point for `resume_unwind`.
|
||||||
pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
|
/// It just forwards the payload to the panic runtime.
|
||||||
|
pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
|
||||||
update_panic_count(1);
|
update_panic_count(1);
|
||||||
|
|
||||||
struct RewrapBox(Box<dyn Any + Send>);
|
struct RewrapBox(Box<dyn Any + Send>);
|
||||||
|
|
||||||
unsafe impl BoxMeUp for RewrapBox {
|
unsafe impl BoxMeUp for RewrapBox {
|
||||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||||
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
|
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,7 +508,7 @@ pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rust_panic(&mut RewrapBox(msg))
|
rust_panic(&mut RewrapBox(payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
|
/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue