Auto merge of #81858 - ijackson:fork-no-unwind, r=m-ou-se
Do not allocate or unwind after fork ### Objective scenarios * Make (simple) panics safe in `Command::pre_exec_hook`, including most `panic!` calls, `Option::unwrap`, and array bounds check failures. * Make it possible to `libc::fork` and then safely panic in the child (needed for the above, but this requirement means exposing the new raw hook API which the `Command` implementation needs). * In singlethreaded programs, where panic in `pre_exec_hook` is already memory-safe, prevent the double-unwinding malfunction #79740. I think we want to make panic after fork safe even though the post-fork child environment is only experienced by users of `unsafe`, beause the subset of Rust in which any panic is UB is really far too hazardous and unnatural. #### Approach * Provide a way for a program to, at runtime, switch to having panics abort. This makes it possible to panic without making *any* heap allocations, which is needed because on some platforms malloc is UB in a child forked from a multithreaded program (see https://github.com/rust-lang/rust/pull/80263#issuecomment-774272370, and maybe also the SuS [spec](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)). * Make that change in the child spawned by `Command`. * Document the rules comprehensively enough that a programmer has a fighting chance of writing correct code. * Test that this all works as expected (and in particular, that there aren't any heap allocations we missed) Fixes #79740 #### Rejected (or previously attempted) approaches * Change the panic machinery to be able to unwind without allocating, at least when the payload and message are both `'static`. This seems like it would be even more subtle. Also that is a potentially-hot path which I don't want to mess with. * Change the existing panic hook mechanism to not convert the message to a `String` before calling the hook. This would be a surprising change for existing code and would not be detected by the type system. * Provide a `raw_panic_hook` function to intercept panics in a way that doesn't allocate. (That was an earlier version of this MR.) ### History This MR could be considered a v2 of #80263. Thanks to everyone who commented there. In particular, thanks to `@m-ou-se,` `@Mark-Simulacrum` and `@hyd-dev.` (Tagging you since I think you might be interested in this new MR.) Compared to #80263, this MR has very substantial changes and additions. Additionally, I have recently (2021-04-20) completely revised this series following very helpful comments from `@m-ou-se.` r? `@m-ou-se`
This commit is contained in:
commit
d565c74887
7 changed files with 333 additions and 39 deletions
|
@ -463,5 +463,41 @@ pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
|
|||
panicking::rust_panic_without_hook(payload)
|
||||
}
|
||||
|
||||
/// Make all future panics abort directly without running the panic hook or unwinding.
|
||||
///
|
||||
/// There is no way to undo this; the effect lasts until the process exits or
|
||||
/// execs (or the equivalent).
|
||||
///
|
||||
/// # Use after fork
|
||||
///
|
||||
/// This function is particularly useful for calling after `libc::fork`. After `fork`, in a
|
||||
/// multithreaded program it is (on many platforms) not safe to call the allocator. It is also
|
||||
/// generally highly undesirable for an unwind to unwind past the `fork`, because that results in
|
||||
/// the unwind propagating to code that was only ever expecting to run in the parent.
|
||||
///
|
||||
/// `panic::always_abort()` helps avoid both of these. It directly avoids any further unwinding,
|
||||
/// and if there is a panic, the abort will occur without allocating provided that the arguments to
|
||||
/// panic can be formatted without allocating.
|
||||
///
|
||||
/// Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(panic_always_abort)]
|
||||
/// use std::panic;
|
||||
///
|
||||
/// panic::always_abort();
|
||||
///
|
||||
/// let _ = panic::catch_unwind(|| {
|
||||
/// panic!("inside the catch");
|
||||
/// });
|
||||
///
|
||||
/// // We will have aborted already, due to the panic.
|
||||
/// unreachable!();
|
||||
/// ```
|
||||
#[unstable(feature = "panic_always_abort", issue = "84438")]
|
||||
pub fn always_abort() {
|
||||
crate::panicking::panic_count::set_always_abort();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue