about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-19 17:05:08 +0000
committerbors <bors@rust-lang.org>2021-06-19 17:05:08 +0000
commit6b354a13820a444f834a33365ae4a8d97d7d27ce (patch)
treed214f382c147bd428359817863efec3056de32d0 /library/std/src
parent29cd70d40722930e66a8b726fe58a7bd1d64a22b (diff)
parent9c9a0da132f9da505d741a733713e3ad5861d84a (diff)
downloadrust-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.rs9
-rw-r--r--library/std/src/rt.rs37
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()
 }