Skip to content

Commit 57d9867

Browse files
authored
Rollup merge of rust-lang#151740 - eggyal:short-backtrace-markers-by-addr, r=joboet
Fix short backtraces from stripped executables Locate the beginning and ending frames for short backtraces by address in addition to symbol name, so that they work even when symbols have been stripped from the executable. We need to retain matching by symbol name for the time being, because rustc (and some associated ui tests) rely upon it to have ICE backtraces abbreviated. They can be updated once this commit lands in beta/stage0. (It is for this reason that the begin/end methods are being publicly exported from `std::backtrace`, albeit hidden from documentation and marked unstable). Fixes rust-lang#147846 r? libs
2 parents 68ea2cf + c8164c0 commit 57d9867

14 files changed

Lines changed: 194 additions & 84 deletions

library/std/src/backtrace.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ use crate::panic::UnwindSafe;
9494
use crate::sync::LazyLock;
9595
use crate::sync::atomic::Ordering::Relaxed;
9696
use crate::sync::atomic::{Atomic, AtomicU8};
97+
#[unstable(
98+
feature = "short_backtrace_controls",
99+
reason = "to control abbreviation of backtraces",
100+
issue = "none"
101+
)]
102+
#[doc(hidden)]
103+
pub use crate::sys::backtrace::{
104+
__rust_begin_short_backtrace as resume_short_backtrace,
105+
__rust_end_short_backtrace as pause_short_backtrace,
106+
};
97107
use crate::sys::backtrace::{lock, output_filename, set_image_base};
98108
use crate::{env, fmt};
99109

library/std/src/sys/backtrace.rs

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
55
use crate::borrow::Cow;
66
use crate::io::prelude::*;
7+
use crate::mem::{ManuallyDrop, MaybeUninit};
78
use crate::path::{self, Path, PathBuf};
89
use crate::sync::{Mutex, MutexGuard, PoisonError};
910
use crate::{env, fmt, io};
@@ -81,12 +82,26 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
8182
let frame_ip = frame.ip();
8283
res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
8384
} else {
85+
// `call_with_end_short_backtrace_marker` means we are done hiding symbols
86+
// for now. Print until we see `call_with_begin_short_backtrace_marker`.
87+
if print_fmt == PrintFmt::Short {
88+
let sym = frame.symbol_address();
89+
if sym == call_with_end_short_backtrace_marker as _ {
90+
print = true;
91+
return true;
92+
} else if print && sym == call_with_begin_short_backtrace_marker as _ {
93+
print = false;
94+
return true;
95+
}
96+
}
97+
8498
let mut hit = false;
8599
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
86100
hit = true;
87101

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.
90105
if print_fmt == PrintFmt::Short {
91106
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
92107
if sym.contains("__rust_end_short_backtrace") {
@@ -155,36 +170,60 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
155170
Ok(())
156171
}
157172

158-
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
159-
/// this is only inline(never) when backtraces in std are enabled, otherwise
160-
/// it's fine to optimize away.
161-
#[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();
173+
macro_rules! short_backtrace_controls {
174+
($($adapter:ident => $marker:ident($unique:literal)),* $(,)?) => {$(
175+
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
176+
/// this is only inline(never) when backtraces in std are enabled, otherwise
177+
/// it's fine to optimize away.
178+
///
179+
/// It is guaranteed that `f` will be called exactly once, and `unsafe` code may
180+
/// rely on this to be the case.
181+
#[cfg_attr(feature = "backtrace", inline(never))]
182+
fn $marker(f: &mut dyn FnMut()) {
183+
f();
184+
185+
// (Try to) prevent both Identical Code Folding (which might merge the different
186+
// versions of this function, giving them the same address) and Tail Call Optimisation
187+
// (which could remove their frames from the call stack).
188+
crate::hint::black_box($unique);
189+
}
167190

168-
// prevent this frame from being tail-call optimised away
169-
crate::hint::black_box(());
191+
/// Invokes `$marker` with an adaptation of `f`, returning its result.
192+
/// This is a more ergonomic interface for placing the marker frame on the stack than
193+
/// the `$marker` function itself. It can be inlined without problem.
194+
#[doc(hidden)]
195+
#[unstable(
196+
feature = "short_backtrace_controls",
197+
reason = "to control abbreviation of backtraces",
198+
issue = "none"
199+
)]
200+
#[inline(always)]
201+
pub fn $adapter<F, T>(f: F) -> T
202+
where
203+
F: FnOnce() -> T,
204+
{
205+
let mut result = MaybeUninit::<T>::uninit();
206+
let mut f = ManuallyDrop::new(f);
170207

171-
result
172-
}
208+
let mut adapted = || {
209+
// SAFETY: `adapted` is called exactly once, by `$marker`;
210+
// and the `ManuallyDrop` is not otherwise used again.
211+
let f = unsafe { ManuallyDrop::take(&mut f) };
212+
result.write(f());
213+
};
173214

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();
215+
$marker(&mut adapted);
183216

184-
// prevent this frame from being tail-call optimised away
185-
crate::hint::black_box(());
217+
// SAFETY: `$marker` guaranteed that it would call `adapted`, which
218+
// initialized `result`.
219+
unsafe { result.assume_init() }
220+
}
221+
)*};
222+
}
186223

187-
result
224+
short_backtrace_controls! {
225+
__rust_begin_short_backtrace => call_with_begin_short_backtrace_marker(0),
226+
__rust_end_short_backtrace => call_with_end_short_backtrace_marker(1),
188227
}
189228

190229
/// Prints the filename of the backtrace frame.

src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,21 @@ LL | crate::process::abort()
1010
= note: stack backtrace:
1111
0: std::alloc::rust_oom::{closure#0}
1212
at RUSTLIB/std/src/alloc.rs:LL:CC
13-
1: std::sys::backtrace::__rust_end_short_backtrace
13+
1: std::backtrace::__rust_end_short_backtrace::{closure#0}
1414
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
15-
2: std::alloc::rust_oom
15+
2: std::sys::backtrace::call_with_end_short_backtrace_marker
16+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
17+
3: std::backtrace::__rust_end_short_backtrace
18+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
19+
4: std::alloc::rust_oom
1620
at RUSTLIB/std/src/alloc.rs:LL:CC
17-
3: std::alloc::_::__rust_alloc_error_handler
21+
5: std::alloc::_::__rust_alloc_error_handler
1822
at RUSTLIB/std/src/alloc.rs:LL:CC
19-
4: std::alloc::handle_alloc_error::rt_error
23+
6: std::alloc::handle_alloc_error::rt_error
2024
at RUSTLIB/alloc/src/alloc.rs:LL:CC
21-
5: std::alloc::handle_alloc_error
25+
7: std::alloc::handle_alloc_error
2226
at RUSTLIB/alloc/src/alloc.rs:LL:CC
23-
6: main
27+
8: main
2428
at tests/fail/alloc/alloc_error_handler.rs:LL:CC
2529

2630
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

src/tools/miri/tests/fail/panic/panic_abort1.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ LL | crate::process::abort();
2020
at RUSTLIB/std/src/panicking.rs:LL:CC
2121
4: std::panicking::panic_handler::{closure#0}
2222
at RUSTLIB/std/src/panicking.rs:LL:CC
23-
5: std::sys::backtrace::__rust_end_short_backtrace
23+
5: std::backtrace::__rust_end_short_backtrace::{closure#0}
2424
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
25-
6: std::panicking::panic_handler
25+
6: std::sys::backtrace::call_with_end_short_backtrace_marker
26+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
27+
7: std::backtrace::__rust_end_short_backtrace
28+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
29+
8: std::panicking::panic_handler
2630
at RUSTLIB/std/src/panicking.rs:LL:CC
27-
7: main
31+
9: main
2832
at RUSTLIB/core/src/panic.rs:LL:CC
2933

3034
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

src/tools/miri/tests/fail/panic/panic_abort2.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ LL | crate::process::abort();
2020
at RUSTLIB/std/src/panicking.rs:LL:CC
2121
4: std::panicking::panic_handler::{closure#0}
2222
at RUSTLIB/std/src/panicking.rs:LL:CC
23-
5: std::sys::backtrace::__rust_end_short_backtrace
23+
5: std::backtrace::__rust_end_short_backtrace::{closure#0}
2424
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
25-
6: std::panicking::panic_handler
25+
6: std::sys::backtrace::call_with_end_short_backtrace_marker
26+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
27+
7: std::backtrace::__rust_end_short_backtrace
28+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
29+
8: std::panicking::panic_handler
2630
at RUSTLIB/std/src/panicking.rs:LL:CC
27-
7: main
31+
9: main
2832
at RUSTLIB/core/src/panic.rs:LL:CC
2933

3034
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

src/tools/miri/tests/fail/panic/panic_abort3.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ LL | crate::process::abort();
2020
at RUSTLIB/std/src/panicking.rs:LL:CC
2121
4: std::panicking::panic_handler::{closure#0}
2222
at RUSTLIB/std/src/panicking.rs:LL:CC
23-
5: std::sys::backtrace::__rust_end_short_backtrace
23+
5: std::backtrace::__rust_end_short_backtrace::{closure#0}
2424
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
25-
6: std::panicking::panic_handler
25+
6: std::sys::backtrace::call_with_end_short_backtrace_marker
26+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
27+
7: std::backtrace::__rust_end_short_backtrace
28+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
29+
8: std::panicking::panic_handler
2630
at RUSTLIB/std/src/panicking.rs:LL:CC
27-
7: main
31+
9: main
2832
at RUSTLIB/core/src/panic.rs:LL:CC
2933

3034
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

src/tools/miri/tests/fail/panic/panic_abort4.stderr

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ LL | crate::process::abort();
2020
at RUSTLIB/std/src/panicking.rs:LL:CC
2121
4: std::panicking::panic_handler::{closure#0}
2222
at RUSTLIB/std/src/panicking.rs:LL:CC
23-
5: std::sys::backtrace::__rust_end_short_backtrace
23+
5: std::backtrace::__rust_end_short_backtrace::{closure#0}
2424
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
25-
6: std::panicking::panic_handler
25+
6: std::sys::backtrace::call_with_end_short_backtrace_marker
26+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
27+
7: std::backtrace::__rust_end_short_backtrace
28+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
29+
8: std::panicking::panic_handler
2630
at RUSTLIB/std/src/panicking.rs:LL:CC
27-
7: main
31+
9: main
2832
at RUSTLIB/core/src/panic.rs:LL:CC
2933

3034
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,33 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
99
= note: stack backtrace:
1010
0: <fn() as std::ops::FnOnce<()>>::call_once - shim(fn())
1111
at RUSTLIB/core/src/ops/function.rs:LL:CC
12-
1: std::sys::backtrace::__rust_begin_short_backtrace
12+
1: std::backtrace::__rust_begin_short_backtrace::{closure#0}
1313
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
14-
2: std::rt::lang_start::{closure#0}
14+
2: std::sys::backtrace::call_with_begin_short_backtrace_marker
15+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
16+
3: std::backtrace::__rust_begin_short_backtrace
17+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
18+
4: std::rt::lang_start::{closure#0}
1519
at RUSTLIB/std/src/rt.rs:LL:CC
16-
3: std::ops::function::impls::call_once
20+
5: std::ops::function::impls::call_once
1721
at RUSTLIB/core/src/ops/function.rs:LL:CC
18-
4: std::panicking::catch_unwind::do_call
22+
6: std::panicking::catch_unwind::do_call
1923
at RUSTLIB/std/src/panicking.rs:LL:CC
20-
5: std::panicking::catch_unwind
24+
7: std::panicking::catch_unwind
2125
at RUSTLIB/std/src/panicking.rs:LL:CC
22-
6: std::panic::catch_unwind
26+
8: std::panic::catch_unwind
2327
at RUSTLIB/std/src/panic.rs:LL:CC
24-
7: std::rt::lang_start_internal::{closure#0}
28+
9: std::rt::lang_start_internal::{closure#0}
2529
at RUSTLIB/std/src/rt.rs:LL:CC
26-
8: std::panicking::catch_unwind::do_call
30+
10: std::panicking::catch_unwind::do_call
2731
at RUSTLIB/std/src/panicking.rs:LL:CC
28-
9: std::panicking::catch_unwind
32+
11: std::panicking::catch_unwind
2933
at RUSTLIB/std/src/panicking.rs:LL:CC
30-
10: std::panic::catch_unwind
34+
12: std::panic::catch_unwind
3135
at RUSTLIB/std/src/panic.rs:LL:CC
32-
11: std::rt::lang_start_internal
36+
13: std::rt::lang_start_internal
3337
at RUSTLIB/std/src/rt.rs:LL:CC
34-
12: std::rt::lang_start
38+
14: std::rt::lang_start
3539
at RUSTLIB/std/src/rt.rs:LL:CC
3640

3741
error: aborting due to 1 previous error

src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_b)
44
tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (func_a)
55
tests/pass/backtrace/backtrace-api-v1.rs:LL:CC (main)
66
RUSTLIB/core/src/ops/function.rs:LL:CC (<fn() as std::ops::FnOnce<()>>::call_once - shim(fn()))
7-
RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace)
7+
RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::backtrace::__rust_begin_short_backtrace::{closure#0})
8+
RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::call_with_begin_short_backtrace_marker)
9+
RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::backtrace::__rust_begin_short_backtrace)
810
RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0})
911
RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
1012
RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind::do_call)

src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22
at tests/pass/backtrace/backtrace-global-alloc.rs:LL:CC
33
1: <fn() as std::ops::FnOnce<()>>::call_once - shim(fn())
44
at RUSTLIB/core/src/ops/function.rs:LL:CC
5-
2: std::sys::backtrace::__rust_begin_short_backtrace
5+
2: std::backtrace::__rust_begin_short_backtrace::{closure#0}
66
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
7-
3: std::rt::lang_start::{closure#0}
7+
3: std::sys::backtrace::call_with_begin_short_backtrace_marker
8+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
9+
4: std::backtrace::__rust_begin_short_backtrace
10+
at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
11+
5: std::rt::lang_start::{closure#0}
812
at RUSTLIB/std/src/rt.rs:LL:CC
9-
4: std::ops::function::impls::call_once
13+
6: std::ops::function::impls::call_once
1014
at RUSTLIB/core/src/ops/function.rs:LL:CC
11-
5: std::panicking::catch_unwind::do_call
15+
7: std::panicking::catch_unwind::do_call
1216
at RUSTLIB/std/src/panicking.rs:LL:CC
13-
6: std::panicking::catch_unwind
17+
8: std::panicking::catch_unwind
1418
at RUSTLIB/std/src/panicking.rs:LL:CC
15-
7: std::panic::catch_unwind
19+
9: std::panic::catch_unwind
1620
at RUSTLIB/std/src/panic.rs:LL:CC
17-
8: std::rt::lang_start_internal::{closure#0}
21+
10: std::rt::lang_start_internal::{closure#0}
1822
at RUSTLIB/std/src/rt.rs:LL:CC
19-
9: std::panicking::catch_unwind::do_call
23+
11: std::panicking::catch_unwind::do_call
2024
at RUSTLIB/std/src/panicking.rs:LL:CC
21-
10: std::panicking::catch_unwind
25+
12: std::panicking::catch_unwind
2226
at RUSTLIB/std/src/panicking.rs:LL:CC
23-
11: std::panic::catch_unwind
27+
13: std::panic::catch_unwind
2428
at RUSTLIB/std/src/panic.rs:LL:CC
25-
12: std::rt::lang_start_internal
29+
14: std::rt::lang_start_internal
2630
at RUSTLIB/std/src/rt.rs:LL:CC
27-
13: std::rt::lang_start
31+
15: std::rt::lang_start
2832
at RUSTLIB/std/src/rt.rs:LL:CC

0 commit comments

Comments
 (0)