about summary refs log tree commit diff
path: root/library/std/src/sys_common
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/sys_common
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/sys_common')
-rw-r--r--library/std/src/sys_common/backtrace.rs39
1 files changed, 34 insertions, 5 deletions
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 {