diff options
| author | bors <bors@rust-lang.org> | 2021-06-19 17:05:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-06-19 17:05:08 +0000 |
| commit | 6b354a13820a444f834a33365ae4a8d97d7d27ce (patch) | |
| tree | d214f382c147bd428359817863efec3056de32d0 /library/std/src | |
| parent | 29cd70d40722930e66a8b726fe58a7bd1d64a22b (diff) | |
| parent | 9c9a0da132f9da505d741a733713e3ad5861d84a (diff) | |
| download | rust-6b354a13820a444f834a33365ae4a8d97d7d27ce.tar.gz rust-6b354a13820a444f834a33365ae4a8d97d7d27ce.zip | |
Auto merge of #86034 - nagisa:nagisa/rt-soundness, r=m-ou-se
Change entry point to 🛡️ against 💥 💥-payloads Guard against panic payloads panicking within entrypoints, where it is UB to do so. Note that there are a number of tradeoffs to consider. For instance, I considered guarding against accidental panics inside the `rt::init` and `rt::cleanup` code as well, as it is not all that obvious these may not panic, but doing so would mean that we initialize certain thread-local slots unconditionally, which has its own problems. Fixes #86030 r? `@m-ou-se`
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/lib.rs | 9 | ||||
| -rw-r--r-- | library/std/src/rt.rs | 37 |
2 files changed, 31 insertions, 15 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 664cc748ca6..1c66dc3648f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -225,13 +225,14 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(async_stream)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] #![feature(assert_matches)] #![feature(associated_type_bounds)] +#![feature(async_stream)] #![feature(atomic_mut_ptr)] +#![feature(auto_traits)] #![feature(bench_black_box)] #![feature(box_syntax)] #![feature(c_variadic)] @@ -244,14 +245,14 @@ #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] -#![feature(const_fn_transmute)] #![feature(const_fn_fn_ptr_basics)] +#![feature(const_fn_transmute)] #![feature(const_io_structs)] #![feature(const_ip)] +#![feature(const_ipv4)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(const_socketaddr)] -#![feature(const_ipv4)] #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] @@ -298,7 +299,6 @@ #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] -#![feature(auto_traits)] #![feature(panic_info_message)] #![feature(panic_internals)] #![feature(panic_unwind)] @@ -330,6 +330,7 @@ #![feature(unboxed_closures)] #![feature(unsafe_cell_raw_get)] #![feature(unwind_attributes)] +#![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] #![feature(vec_spare_capacity)] // NB: the above list is sorted to minimize merge conflicts. diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 1e19aff51f8..72e6c23ee49 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -24,18 +24,32 @@ fn lang_start_internal( main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), argc: isize, argv: *const *const u8, -) -> isize { - use crate::panic; - use crate::sys_common; - +) -> Result<isize, !> { + use crate::{mem, panic, sys, sys_common}; + let rt_abort = move |e| { + mem::forget(e); + rtabort!("initialization or cleanup bug"); + }; + // Guard against the code called by this function from unwinding outside of the Rust-controlled + // code, which is UB. This is a requirement imposed by a combination of how the + // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking + // mechanism itself. + // + // There are a couple of instances where unwinding can begin. First is inside of the + // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a + // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to + // prevent libstd from accidentally introducing a panic to these functions. Another is from + // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - unsafe { sys_common::rt::init(argc, argv) }; - - let exit_code = panic::catch_unwind(main); - - sys_common::rt::cleanup(); - - exit_code.unwrap_or(101) as isize + panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?; + let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) + .map_err(move |e| { + mem::forget(e); + rtprintpanic!("drop of the panic payload panicked"); + sys::abort_internal() + }); + panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?; + ret_code } #[cfg(not(test))] @@ -50,4 +64,5 @@ fn lang_start<T: crate::process::Termination + 'static>( argc, argv, ) + .into_ok() } |
