Skip to content

Commit 609fee7

Browse files
committed
Ignore panic related functions, functions before main and thread entry points in backtraces
1 parent 1699293 commit 609fee7

File tree

10 files changed

+108
-62
lines changed

10 files changed

+108
-62
lines changed

src/libcore/panicking.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,38 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
4848
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
4949
// output binary, saving up to a few kilobytes.
5050
let (expr, file, line, col) = *expr_file_line_col;
51-
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col))
51+
panic_dispatch(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col), &(panic as usize))
5252
}
5353

5454
#[cold] #[inline(never)]
5555
#[lang = "panic_bounds_check"]
5656
fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
57-
index: usize, len: usize) -> ! {
58-
panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
59-
len, index), file_line_col)
57+
index: usize, len: usize) -> ! {
58+
panic_dispatch(format_args!("index out of bounds: the len is {} but the index is {}",
59+
len, index),
60+
file_line_col,
61+
&(panic_bounds_check as usize))
6062
}
6163

6264
#[cold] #[inline(never)]
6365
pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
66+
panic_dispatch(fmt, file_line_col, &(panic_fmt as usize));
67+
}
68+
69+
#[cold]
70+
fn panic_dispatch(fmt: fmt::Arguments,
71+
file_line_col: &(&'static str, u32, u32),
72+
entry_point: &usize) -> ! {
6473
#[allow(improper_ctypes)]
6574
extern {
6675
#[lang = "panic_fmt"]
6776
#[unwind]
68-
fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !;
77+
fn panic_impl(fmt: fmt::Arguments,
78+
file: &'static str,
79+
line: u32,
80+
col: u32,
81+
entry_point: &usize) -> !;
6982
}
7083
let (file, line, col) = *file_line_col;
71-
unsafe { panic_impl(fmt, file, line, col) }
72-
}
84+
unsafe { panic_impl(fmt, file, line, col, entry_point) }
85+
}

src/libstd/panicking.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
181181
pub struct PanicInfo<'a> {
182182
payload: &'a (Any + Send),
183183
location: Location<'a>,
184+
entry_point: usize,
184185
}
185186

186187
impl<'a> PanicInfo<'a> {
@@ -378,7 +379,7 @@ fn default_hook(info: &PanicInfo) {
378379
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
379380

380381
if let Some(format) = log_backtrace {
381-
let _ = backtrace::print(err, format);
382+
let _ = backtrace::print(err, format, info.entry_point);
382383
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
383384
let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
384385
}
@@ -494,8 +495,9 @@ pub fn panicking() -> bool {
494495
pub extern fn rust_begin_panic(msg: fmt::Arguments,
495496
file: &'static str,
496497
line: u32,
497-
col: u32) -> ! {
498-
begin_panic_fmt(&msg, &(file, line, col))
498+
col: u32,
499+
entry_point: &usize) -> ! {
500+
rust_panic_fmt(&msg, &(file, line, col), entry_point)
499501
}
500502

501503
/// The entry point for panicking with a formatted message.
@@ -508,8 +510,14 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments,
508510
reason = "used by the panic! macro",
509511
issue = "0")]
510512
#[inline(never)] #[cold]
511-
pub fn begin_panic_fmt(msg: &fmt::Arguments,
512-
file_line_col: &(&'static str, u32, u32)) -> ! {
513+
pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
514+
rust_panic_fmt(msg, file_line_col, &(begin_panic_fmt as usize))
515+
}
516+
517+
#[cold]
518+
fn rust_panic_fmt(msg: &fmt::Arguments,
519+
file_line_col: &(&'static str, u32, u32),
520+
entry_point: &usize) -> ! {
513521
use fmt::Write;
514522

515523
// We do two allocations here, unfortunately. But (a) they're
@@ -519,7 +527,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments,
519527

520528
let mut s = String::new();
521529
let _ = s.write_fmt(*msg);
522-
begin_panic(s, file_line_col)
530+
rust_panic_with_hook(Box::new(s), file_line_col, entry_point)
523531
}
524532

525533
/// This is the entry point of panicking for panic!() and assert!().
@@ -535,7 +543,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
535543
// be performed in the parent of this thread instead of the thread that's
536544
// panicking.
537545

538-
rust_panic_with_hook(Box::new(msg), file_line_col)
546+
rust_panic_with_hook(Box::new(msg), file_line_col, &(begin_panic::<M> as usize))
539547
}
540548

541549
/// Executes the primary logic for a panic, including checking for recursive
@@ -546,8 +554,9 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
546554
/// run panic hooks, and then delegate to the actual implementation of panics.
547555
#[inline(never)]
548556
#[cold]
549-
fn rust_panic_with_hook(msg: Box<Any + Send>,
550-
file_line_col: &(&'static str, u32, u32)) -> ! {
557+
pub(crate) fn rust_panic_with_hook(msg: Box<Any + Send>,
558+
file_line_col: &(&'static str, u32, u32),
559+
entry_point: &usize) -> ! {
551560
let (file, line, col) = *file_line_col;
552561

553562
let panics = update_panic_count(1);
@@ -571,6 +580,7 @@ fn rust_panic_with_hook(msg: Box<Any + Send>,
571580
line,
572581
col,
573582
},
583+
entry_point: *entry_point,
574584
};
575585
HOOK_LOCK.read();
576586
match HOOK {

src/libstd/rt.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
5656
// Let's run some code!
5757
#[cfg(feature = "backtrace")]
5858
let res = panic::catch_unwind(|| {
59-
::sys_common::backtrace::__rust_begin_short_backtrace(main)
59+
let mut main = main;
60+
::sys_common::backtrace::mark_start(&mut main)
6061
});
6162
#[cfg(not(feature = "backtrace"))]
6263
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));

src/libstd/sys/unix/backtrace/printing/dladdr.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ use sys_common::backtrace::Frame;
1818
pub fn resolve_symname<F>(frame: Frame,
1919
callback: F,
2020
_: &BacktraceContext) -> io::Result<()>
21-
where F: FnOnce(Option<&str>) -> io::Result<()>
21+
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
2222
{
2323
unsafe {
2424
let mut info: Dl_info = intrinsics::init();
25-
let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
25+
let symninfo = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
2626
info.dli_sname.is_null() {
2727
None
2828
} else {
29-
CStr::from_ptr(info.dli_sname).to_str().ok()
29+
CStr::from_ptr(info.dli_sname).to_str().ok().map(|s| (s, info.dli_saddr as usize))
3030
};
31-
callback(symname)
31+
callback(syminfo)
3232
}
3333
}
3434

src/libstd/sys/unix/backtrace/printing/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline;
3131
#[cfg(not(target_os = "emscripten"))]
3232
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
3333
where
34-
F: FnOnce(Option<&str>) -> io::Result<()>
34+
F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
3535
{
36-
::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
37-
if symname.is_some() {
38-
callback(symname)
36+
::sys_common::gnu::libbacktrace::resolve_symname(frame, |syminfo| {
37+
if syminfo.is_some() {
38+
callback(syminfo)
3939
} else {
4040
dladdr::resolve_symname(frame, callback, bc)
4141
}

src/libstd/sys/windows/backtrace/printing/msvc.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type SymGetLineFromAddr64Fn =
2727
pub fn resolve_symname<F>(frame: Frame,
2828
callback: F,
2929
context: &BacktraceContext) -> io::Result<()>
30-
where F: FnOnce(Option<&str>) -> io::Result<()>
30+
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
3131
{
3232
let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
3333

@@ -45,13 +45,15 @@ pub fn resolve_symname<F>(frame: Frame,
4545
&mut displacement,
4646
&mut info);
4747

48-
let symname = if ret == c::TRUE {
48+
let syminfo = if ret == c::TRUE {
4949
let ptr = info.Name.as_ptr() as *const c_char;
50-
CStr::from_ptr(ptr).to_str().ok()
50+
CStr::from_ptr(ptr).to_str().ok().map(|s| {
51+
(s, (frame.symbol_addr as usize).wrapping_sub(displacement as usize))
52+
})
5153
} else {
5254
None
5355
};
54-
callback(symname)
56+
callback(syminfo)
5557
}
5658
}
5759

src/libstd/sys_common/backtrace.rs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,27 @@ pub struct Frame {
4747
const MAX_NB_FRAMES: usize = 100;
4848

4949
/// Prints the current backtrace.
50-
pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
50+
pub fn print(w: &mut Write, format: PrintFormat, entry_point: usize) -> io::Result<()> {
5151
static LOCK: Mutex = Mutex::new();
5252

5353
// Use a lock to prevent mixed output in multithreading context.
5454
// Some platforms also requires it, like `SymFromAddr` on Windows.
5555
unsafe {
5656
LOCK.lock();
57-
let res = _print(w, format);
57+
let res = _print(w, format, entry_point);
5858
LOCK.unlock();
5959
res
6060
}
6161
}
6262

63-
fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
63+
fn _print(w: &mut Write, format: PrintFormat, entry_point: usize) -> io::Result<()> {
6464
let mut frames = [Frame {
6565
exact_position: ptr::null(),
6666
symbol_addr: ptr::null(),
6767
}; MAX_NB_FRAMES];
6868
let (nb_frames, context) = unwind_backtrace(&mut frames)?;
6969
let (skipped_before, skipped_after) =
70-
filter_frames(&frames[..nb_frames], format, &context);
70+
filter_frames(&frames[..nb_frames], format, &context, entry_point);
7171
if skipped_before + skipped_after > 0 {
7272
writeln!(w, "note: Some details are omitted, \
7373
run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
@@ -76,8 +76,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
7676

7777
let filtered_frames = &frames[..nb_frames - skipped_after];
7878
for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
79-
resolve_symname(*frame, |symname| {
80-
output(w, index, *frame, symname, format)
79+
resolve_symname(*frame, |syminfo| {
80+
output(w, index, *frame, syminfo.map(|i| i.0), format)
8181
}, &context)?;
8282
let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
8383
output_fileline(w, file, line, format)
@@ -94,27 +94,32 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
9494
/// backtrace, according to the backtrace format.
9595
fn filter_frames(frames: &[Frame],
9696
format: PrintFormat,
97-
context: &BacktraceContext) -> (usize, usize)
97+
context: &BacktraceContext,
98+
entry_point: usize) -> (usize, usize)
9899
{
99100
if format == PrintFormat::Full {
100101
return (0, 0);
101102
}
102103

103-
let skipped_before = 0;
104+
let skipped_before = frames.iter().position(|frame| {
105+
let mut addr = None;
106+
let _ = resolve_symname(*frame, |syminfo| {
107+
addr = syminfo.map(|a| a.1);
108+
Ok(())
109+
}, context);
110+
addr == Some(entry_point)
111+
}).map(|p| p + 1).unwrap_or(0);
104112

105-
let skipped_after = frames.len() - frames.iter().position(|frame| {
113+
let skipped_after = frames.iter().rev().position(|frame| {
106114
let mut is_marker = false;
107-
let _ = resolve_symname(*frame, |symname| {
108-
if let Some(mangled_symbol_name) = symname {
109-
// Use grep to find the concerned functions
110-
if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
111-
is_marker = true;
112-
}
115+
let _ = resolve_symname(*frame, |syminfo| {
116+
if syminfo.map(|i| i.1) == Some(MARK_START.0 as usize) {
117+
is_marker = true;
113118
}
114119
Ok(())
115120
}, context);
116121
is_marker
117-
}).unwrap_or(frames.len());
122+
}).map(|p| p + 1).unwrap_or(0);
118123

119124
if skipped_before + skipped_after >= frames.len() {
120125
// Avoid showing completely empty backtraces
@@ -124,13 +129,19 @@ fn filter_frames(frames: &[Frame],
124129
(skipped_before, skipped_after)
125130
}
126131

132+
#[derive(Eq, PartialEq)]
133+
struct Function(*const ());
134+
unsafe impl Sync for Function {}
135+
136+
static MARK_START: Function = Function(mark_start as *const ());
127137

128-
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
138+
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`
129139
#[inline(never)]
130-
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
131-
where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
132-
{
133-
f()
140+
pub fn mark_start(f: &mut FnMut()) {
141+
f();
142+
unsafe {
143+
asm!("" ::: "memory" : "volatile"); // A dummy statement to prevent tail call optimization
144+
}
134145
}
135146

136147
/// Controls how the backtrace should be formated.

src/libstd/sys_common/gnu/libbacktrace.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,34 +63,34 @@ where F: FnMut(&[u8], u32) -> io::Result<()>
6363
pub fn resolve_symname<F>(frame: Frame,
6464
callback: F,
6565
_: &BacktraceContext) -> io::Result<()>
66-
where F: FnOnce(Option<&str>) -> io::Result<()>
66+
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
6767
{
68-
let symname = {
68+
let syminfo = {
6969
let state = unsafe { init_state() };
7070
if state.is_null() {
7171
return Err(io::Error::new(
7272
io::ErrorKind::Other,
7373
"failed to allocate libbacktrace state")
7474
)
7575
}
76-
let mut data = ptr::null();
77-
let data_addr = &mut data as *mut *const libc::c_char;
76+
let mut data = (ptr::null(), 0);
77+
let data_addr = &mut data as *mut _;
7878
let ret = unsafe {
7979
backtrace_syminfo(state,
8080
frame.symbol_addr as libc::uintptr_t,
8181
syminfo_cb,
8282
error_cb,
8383
data_addr as *mut libc::c_void)
8484
};
85-
if ret == 0 || data.is_null() {
85+
if ret == 0 || data.0.is_null() {
8686
None
8787
} else {
8888
unsafe {
89-
CStr::from_ptr(data).to_str().ok()
89+
CStr::from_ptr(data.0).to_str().ok().map(|s| (s, data.1))
9090
}
9191
}
9292
};
93-
callback(symname)
93+
callback(syminfo)
9494
}
9595

9696
////////////////////////////////////////////////////////////////////////
@@ -145,10 +145,10 @@ extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
145145
extern fn syminfo_cb(data: *mut libc::c_void,
146146
_pc: libc::uintptr_t,
147147
symname: *const libc::c_char,
148-
_symval: libc::uintptr_t,
148+
symval: libc::uintptr_t,
149149
_symsize: libc::uintptr_t) {
150-
let slot = data as *mut *const libc::c_char;
151-
unsafe { *slot = symname; }
150+
let slot = data as *mut (*const libc::c_char, usize);
151+
unsafe { *slot = (symname, symval); }
152152
}
153153
extern fn pcinfo_cb(data: *mut libc::c_void,
154154
_pc: libc::uintptr_t,

src/libstd/thread/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,13 @@ impl Builder {
403403
thread_info::set(imp::guard::current(), their_thread);
404404
#[cfg(feature = "backtrace")]
405405
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
406-
::sys_common::backtrace::__rust_begin_short_backtrace(f)
406+
let mut f = Some(f);
407+
let mut r = None;
408+
::sys_common::backtrace::mark_start(&mut || {
409+
let f = f.take().unwrap();
410+
r = Some(f());
411+
});
412+
r.unwrap()
407413
}));
408414
#[cfg(not(feature = "backtrace"))]
409415
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));

0 commit comments

Comments
 (0)