|
4 | 4 | use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; |
5 | 5 | use crate::borrow::Cow; |
6 | 6 | use crate::io::prelude::*; |
| 7 | +use crate::mem::{ManuallyDrop, MaybeUninit}; |
7 | 8 | use crate::path::{self, Path, PathBuf}; |
8 | 9 | use crate::sync::{Mutex, MutexGuard, PoisonError}; |
9 | 10 | use crate::{env, fmt, io}; |
@@ -81,12 +82,26 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: |
81 | 82 | let frame_ip = frame.ip(); |
82 | 83 | res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); |
83 | 84 | } else { |
| 85 | + // `call_with_short_backtrace_marker::<End>` means we are done hiding symbols |
| 86 | + // for now. Print until we see `call_with_short_backtrace_marker::<Begin>`. |
| 87 | + if print_fmt == PrintFmt::Short { |
| 88 | + let sym = frame.symbol_address(); |
| 89 | + if sym == call_with_short_backtrace_marker::<End> as _ { |
| 90 | + print = true; |
| 91 | + return true; |
| 92 | + } else if print && sym == call_with_short_backtrace_marker::<Begin> as _ { |
| 93 | + print = false; |
| 94 | + return true; |
| 95 | + } |
| 96 | + } |
| 97 | + |
84 | 98 | let mut hit = false; |
85 | 99 | backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { |
86 | 100 | hit = true; |
87 | 101 |
|
88 | | - // `__rust_end_short_backtrace` means we are done hiding symbols |
89 | | - // for now. Print until we see `__rust_begin_short_backtrace`. |
| 102 | + // Hide `__rust_[begin|end]_short_backtrace` frames from short backtraces. |
| 103 | + // Unfortunately these generic functions have to be matched by name, as we do |
| 104 | + // not know their generic parameters. |
90 | 105 | if print_fmt == PrintFmt::Short { |
91 | 106 | if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { |
92 | 107 | if sym.contains("__rust_end_short_backtrace") { |
@@ -159,32 +174,45 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: |
159 | 174 | /// this is only inline(never) when backtraces in std are enabled, otherwise |
160 | 175 | /// it's fine to optimize away. |
161 | 176 | #[cfg_attr(feature = "backtrace", inline(never))] |
162 | | -pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T |
163 | | -where |
164 | | - F: FnOnce() -> T, |
165 | | -{ |
166 | | - let result = f(); |
| 177 | +fn call_with_short_backtrace_marker<T: Terminus>(f: &mut dyn FnMut()) { |
| 178 | + f(); |
167 | 179 |
|
168 | | - // prevent this frame from being tail-call optimised away |
169 | | - crate::hint::black_box(()); |
| 180 | + // (Try to) prevent both Identical Code Folding (which might merge the `Begin` and `End` |
| 181 | + // versions of this function, giving them the same address) and Tail Call Optimisation (which |
| 182 | + // could remove their frames from the call stack). |
| 183 | + crate::hint::black_box(T::ID); |
| 184 | +} |
170 | 185 |
|
171 | | - result |
| 186 | +trait Terminus { |
| 187 | + const ID: u32; |
172 | 188 | } |
173 | 189 |
|
174 | | -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that |
175 | | -/// this is only inline(never) when backtraces in std are enabled, otherwise |
176 | | -/// it's fine to optimize away. |
177 | | -#[cfg_attr(feature = "backtrace", inline(never))] |
178 | | -pub fn __rust_end_short_backtrace<F, T>(f: F) -> T |
179 | | -where |
180 | | - F: FnOnce() -> T, |
181 | | -{ |
182 | | - let result = f(); |
| 190 | +macro_rules! short_backtrace_termini { |
| 191 | + ($($f:ident => $t:ident($id:literal)),* $(,)?) => {$( |
| 192 | + struct $t; |
| 193 | + impl Terminus for $t { |
| 194 | + const ID: u32 = $id; |
| 195 | + } |
183 | 196 |
|
184 | | - // prevent this frame from being tail-call optimised away |
185 | | - crate::hint::black_box(()); |
| 197 | + #[doc(hidden)] |
| 198 | + #[unstable(feature = "short_backtrace_termini", reason = "for rustc to have ICE backtraces abbreviated", issue = "none")] |
| 199 | + #[inline(always)] |
| 200 | + pub fn $f<F, T>(f: F) -> T |
| 201 | + where |
| 202 | + F: FnOnce() -> T, |
| 203 | + { |
| 204 | + let mut result = MaybeUninit::<T>::uninit(); |
| 205 | + let mut f = ManuallyDrop::new(f); |
| 206 | + let mut f = || { result.write(unsafe { ManuallyDrop::take(&mut f) }()); }; |
| 207 | + call_with_short_backtrace_marker::<$t>(&mut f); |
| 208 | + unsafe { result.assume_init() } |
| 209 | + } |
| 210 | + )*}; |
| 211 | +} |
186 | 212 |
|
187 | | - result |
| 213 | +short_backtrace_termini! { |
| 214 | + __rust_begin_short_backtrace => Begin(0), |
| 215 | + __rust_end_short_backtrace => End(1), |
188 | 216 | } |
189 | 217 |
|
190 | 218 | /// Prints the filename of the backtrace frame. |
|
0 commit comments