about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorAlan Egerton <eggyal@gmail.com>2020-08-04 22:18:20 +0100
committerAlan Egerton <eggyal@gmail.com>2020-08-07 19:31:25 +0100
commit5792840bf52e4cf77ebb7b3bd93e9c90dd23f4e7 (patch)
treea3bfeaade21999a1b1bba131225ba0238e767d19 /library/std/src
parent4d4342347b71313258a46e506ee0a258f365185c (diff)
downloadrust-5792840bf52e4cf77ebb7b3bd93e9c90dd23f4e7.tar.gz
rust-5792840bf52e4cf77ebb7b3bd93e9c90dd23f4e7.zip
Prevent `__rust_begin_short_backtrace` frames from being tail-call optimised away
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/panicking.rs9
-rw-r--r--library/std/src/rt.rs10
-rw-r--r--library/std/src/sys_common/backtrace.rs39
3 files changed, 47 insertions, 11 deletions
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index ab2a6010306..21ab0faed3e 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -434,7 +434,9 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
 
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
-    rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+    crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+        rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+    })
 }
 
 /// This is the entry point of panicking for the non-format-string variants of
@@ -453,7 +455,10 @@ pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
         intrinsics::abort()
     }
 
-    rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller());
+    let loc = Location::caller();
+    return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+    });
 
     struct PanicPayload<A> {
         inner: Option<A>,
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index fb825ab16eb..45af9f68a0f 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -48,9 +48,7 @@ fn lang_start_internal(
         sys::args::init(argc, argv);
 
         // Let's run some code!
-        let exit_code = panic::catch_unwind(|| {
-            sys_common::backtrace::__rust_begin_short_backtrace(move || main())
-        });
+        let exit_code = panic::catch_unwind(main);
 
         sys_common::cleanup();
         exit_code.unwrap_or(101) as isize
@@ -64,5 +62,9 @@ fn lang_start<T: crate::process::Termination + 'static>(
     argc: isize,
     argv: *const *const u8,
 ) -> isize {
-    lang_start_internal(&move || main().report(), argc, argv)
+    lang_start_internal(
+        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
+        argc,
+        argv,
+    )
 }
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index d386a656e4f..1c5fbf7d701 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -74,6 +74,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
     bt_fmt.add_context()?;
     let mut idx = 0;
     let mut res = Ok(());
+    // Start immediately if we're not using a short backtrace.
+    let mut start = print_fmt != PrintFmt::Short;
     backtrace_rs::trace_unsynchronized(|frame| {
         if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
             return false;
@@ -89,16 +91,24 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                         stop = true;
                         return;
                     }
+                    if sym.contains("__rust_end_short_backtrace") {
+                        start = true;
+                        return;
+                    }
                 }
             }
 
-            res = bt_fmt.frame().symbol(frame, symbol);
+            if start {
+                res = bt_fmt.frame().symbol(frame, symbol);
+            }
         });
         if stop {
             return false;
         }
         if !hit {
-            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+            if start {
+                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+            }
         }
 
         idx += 1;
@@ -123,10 +133,29 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
 where
     F: FnOnce() -> T,
-    F: Send,
-    T: Send,
 {
-    f()
+    let result = f();
+
+    // prevent this frame from being tail-call optimised away
+    crate::hint::black_box(());
+
+    result
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
+/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// it's fine to optimize away.
+#[cfg_attr(feature = "backtrace", inline(never))]
+pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
+where
+    F: FnOnce() -> T,
+{
+    let result = f();
+
+    // prevent this frame from being tail-call optimised away
+    crate::hint::black_box(());
+
+    result
 }
 
 pub enum RustBacktrace {