Skip to content

Commit 4df5929

Browse files
committed
Ignore panic related functions in backtraces. Also fixes __rust_begin_short_backtrace
1 parent fa0b944 commit 4df5929

File tree

12 files changed

+99
-41
lines changed

12 files changed

+99
-41
lines changed

src/libcore/panicking.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
5353

5454
#[cold] #[inline(never)]
5555
#[lang = "panic_bounds_check"]
56-
fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
56+
pub fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
5757
index: usize, len: usize) -> ! {
5858
panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
5959
len, index), file_line_col)

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@
265265
#![feature(const_ptr_null_mut)]
266266
#![feature(core_float)]
267267
#![feature(core_intrinsics)]
268+
#![feature(core_panic)]
268269
#![feature(dropck_eyepatch)]
269270
#![feature(exact_size_is_empty)]
270271
#![feature(float_from_str_radix)]

src/libstd/macros.rs

+22
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@
5858
/// panic!(4); // panic with the value of 4 to be collected elsewhere
5959
/// panic!("this is a {} {message}", "fancy", message = "message");
6060
/// ```
61+
#[cfg(not(stage0))]
62+
#[macro_export]
63+
#[stable(feature = "rust1", since = "1.0.0")]
64+
#[allow_internal_unstable]
65+
macro_rules! panic {
66+
() => ({
67+
panic!("explicit panic")
68+
});
69+
($msg:str) => ({
70+
$crate::rt::begin_panic_str(&($msg, file!(), line!(), __rust_unstable_column!()))
71+
});
72+
($msg:expr) => ({
73+
$crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!()))
74+
});
75+
($fmt:expr, $($arg:tt)+) => ({
76+
$crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+),
77+
&(file!(), line!(), __rust_unstable_column!()))
78+
});
79+
}
80+
81+
/// docs
82+
#[cfg(stage0)]
6183
#[macro_export]
6284
#[stable(feature = "rust1", since = "1.0.0")]
6385
#[allow_internal_unstable]

src/libstd/panicking.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,16 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments,
498498
begin_panic_fmt(&msg, &(file, line, col))
499499
}
500500

501+
/// This is the entry point of panicking for string literals.
502+
#[unstable(feature = "libstd_sys_internals",
503+
reason = "used by the panic! macro",
504+
issue = "0")]
505+
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
506+
pub fn begin_panic_str(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
507+
let (expr, file, line, col) = *expr_file_line_col;
508+
begin_panic(expr, &(file, line, col))
509+
}
510+
501511
/// The entry point for panicking with a formatted message.
502512
///
503513
/// This is designed to reduce the amount of code required at the call
@@ -535,6 +545,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
535545
// be performed in the parent of this thread instead of the thread that's
536546
// panicking.
537547

548+
// We want this call to get tail call optimized so `begin_panic` do not appear in backtraces
538549
rust_panic_with_hook(Box::new(msg), file_line_col)
539550
}
540551

@@ -546,8 +557,8 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
546557
/// run panic hooks, and then delegate to the actual implementation of panics.
547558
#[inline(never)]
548559
#[cold]
549-
fn rust_panic_with_hook(msg: Box<Any + Send>,
550-
file_line_col: &(&'static str, u32, u32)) -> ! {
560+
pub(crate) fn rust_panic_with_hook(msg: Box<Any + Send>,
561+
file_line_col: &(&'static str, u32, u32)) -> ! {
551562
let (file, line, col) = *file_line_col;
552563

553564
let panics = update_panic_count(1);

src/libstd/rt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626

2727
// Reexport some of our utilities which are expected by other crates.
28-
pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
28+
pub use panicking::{begin_panic_str, begin_panic_fmt, begin_panic, update_panic_count};
2929

3030
#[cfg(not(test))]
3131
#[lang = "start"]
@@ -57,7 +57,7 @@ fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
5757
// Let's run some code!
5858
#[cfg(feature = "backtrace")]
5959
let res = panic::catch_unwind(|| {
60-
::sys_common::backtrace::__rust_begin_short_backtrace(main)
60+
::sys_common::backtrace::__rust_begin_short_backtrace(main).0
6161
});
6262
#[cfg(not(feature = "backtrace"))]
6363
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main));

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

+4-4
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, &mut info) == 0 ||
25+
let syminfo = if dladdr(frame.exact_position, &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, nfo.dli_saddr as usize))
3030
};
31-
callback(symname)
31+
callback(syminfo);
3232
}
3333
}
3434

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

+3-3
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| {
36+
::sys_common::gnu::libbacktrace::resolve_symname(frame, |syminfo| {
3737
if symname.is_some() {
38-
callback(symname)
38+
callback(syminfo)
3939
} else {
4040
dladdr::resolve_symname(frame, callback, bc)
4141
}

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

+6-4
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

+29-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use io::prelude::*;
1616
use io;
1717
use libc;
1818
use str;
19+
use core;
20+
use panicking;
1921
use sync::atomic::{self, Ordering};
2022
use path::{self, Path};
2123
use sys::mutex::Mutex;
@@ -77,8 +79,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
7779

7880
let filtered_frames = &frames[..nb_frames - skipped_after];
7981
for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
80-
resolve_symname(*frame, |symname| {
81-
output(w, index, *frame, symname, format)
82+
resolve_symname(*frame, |syminfo| {
83+
output(w, index, *frame, syminfo.map(|i| i.0), format)
8284
}, &context)?;
8385
let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
8486
output_fileline(w, file, line, format)
@@ -101,12 +103,32 @@ fn filter_frames(frames: &[Frame],
101103
return (0, 0);
102104
}
103105

104-
let skipped_before = 0;
106+
#[derive(Eq, PartialEq)]
107+
struct Function(*const ());
108+
unsafe impl Sync for Function {}
109+
110+
static PANIC_FUNCTIONS: &[Function] = &[
111+
Function(core::panicking::panic as *const ()),
112+
Function(core::panicking::panic_bounds_check as *const ()),
113+
Function(core::panicking::panic_fmt as *const ()),
114+
Function(panicking::begin_panic_str as *const ()),
115+
Function(panicking::begin_panic_fmt as *const ()),
116+
Function(panicking::rust_panic_with_hook as *const ()),
117+
];
118+
119+
let skipped_before = frames.len() - frames.iter().rev().position(|frame| {
120+
let mut addr = None;
121+
resolve_symname(*frame, |syminfo| {
122+
addr = syminfo.map(|a| a.1);
123+
Ok(())
124+
}, context).ok();
125+
addr.map(|a| PANIC_FUNCTIONS.contains(&Function(a as *const ()))).unwrap_or(false)
126+
}).unwrap_or(frames.len());
105127

106128
let skipped_after = frames.len() - frames.iter().position(|frame| {
107129
let mut is_marker = false;
108-
let _ = resolve_symname(*frame, |symname| {
109-
if let Some(mangled_symbol_name) = symname {
130+
let _ = resolve_symname(*frame, |syminfo| {
131+
if let Some((mangled_symbol_name, _)) = syminfo {
110132
// Use grep to find the concerned functions
111133
if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
112134
is_marker = true;
@@ -125,13 +147,12 @@ fn filter_frames(frames: &[Frame],
125147
(skipped_before, skipped_after)
126148
}
127149

128-
129150
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
130151
#[inline(never)]
131-
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
152+
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> (T, usize)
132153
where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
133154
{
134-
f()
155+
(f(), 0) // The number is a dummy return value to prevent tail call optimization
135156
}
136157

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

src/libstd/sys_common/gnu/libbacktrace.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -63,34 +63,34 @@ where F: FnMut(&[u8], libc::c_int) -> 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(), usize);
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).to_str().ok(), 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

+1-1
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ impl Builder {
399399
thread_info::set(imp::guard::current(), their_thread);
400400
#[cfg(feature = "backtrace")]
401401
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
402-
::sys_common::backtrace::__rust_begin_short_backtrace(f)
402+
::sys_common::backtrace::__rust_begin_short_backtrace(f).0
403403
}));
404404
#[cfg(not(feature = "backtrace"))]
405405
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));

src/libtest/lib.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1355,14 +1355,14 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
13551355
DynBenchFn(bench) => {
13561356
DynTestFn(Box::new(move |()| {
13571357
bench::run_once(|b| {
1358-
__rust_begin_short_backtrace(|| bench.run(b))
1358+
__rust_begin_short_backtrace(|| bench.run(b));
13591359
})
13601360
}))
13611361
}
13621362
StaticBenchFn(benchfn) => {
13631363
DynTestFn(Box::new(move |()| {
13641364
bench::run_once(|b| {
1365-
__rust_begin_short_backtrace(|| benchfn(b))
1365+
__rust_begin_short_backtrace(|| benchfn(b));
13661366
})
13671367
}))
13681368
}
@@ -1471,20 +1471,21 @@ pub fn run_test(opts: &TestOpts,
14711471
}
14721472
DynTestFn(f) => {
14731473
let cb = move |()| {
1474-
__rust_begin_short_backtrace(|| f.call_box(()))
1474+
__rust_begin_short_backtrace(|| f.call_box(()));
14751475
};
14761476
run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb))
14771477
}
14781478
StaticTestFn(f) =>
14791479
run_test_inner(desc, monitor_ch, opts.nocapture,
1480-
Box::new(move |()| __rust_begin_short_backtrace(f))),
1480+
Box::new(move |()| {__rust_begin_short_backtrace(f); })),
14811481
}
14821482
}
14831483

14841484
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
14851485
#[inline(never)]
1486-
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
1487-
f()
1486+
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) -> usize {
1487+
f();
1488+
0 // A dummy return value to prevent tail call optimization
14881489
}
14891490

14901491
fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> TestResult {

0 commit comments

Comments
 (0)