1
Fork 0

Don't show the std frames before user code on unwinding.

When `RUST_BACKTRACE=1`, remove all frames after
`__rust_maybe_catch_panic`. Tested on `main`, threads, tests and
benches. Cleaning of the top of the stacktrace is let to a future PR.

Fixes #40201

See #41815
This commit is contained in:
Yamakaky 2017-03-04 10:27:52 -05:00
parent f3fc547194
commit ca8b75466c
No known key found for this signature in database
GPG key ID: 1F5120C66C0B64F7
4 changed files with 68 additions and 13 deletions

View file

@ -29,8 +29,7 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};
#[cfg(not(test))] #[cfg(not(test))]
#[lang = "start"] #[lang = "start"]
fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize {
use mem;
use panic; use panic;
use sys; use sys;
use sys_common; use sys_common;
@ -54,7 +53,9 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
sys::args::init(argc, argv); sys::args::init(argc, argv);
// Let's run some code! // Let's run some code!
let res = panic::catch_unwind(mem::transmute::<_, fn()>(main)); let res = panic::catch_unwind(|| {
::sys_common::backtrace::__rust_begin_short_backtrace(main)
});
sys_common::cleanup(); sys_common::cleanup();
res.is_err() res.is_err()
}; };

View file

@ -93,11 +93,47 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
Ok(()) Ok(())
} }
fn filter_frames(_frames: &[Frame], /// Returns a number of frames to remove at the beginning and at the end of the
_format: PrintFormat, /// backtrace, according to the backtrace format.
_context: &BacktraceContext) -> (usize, usize) fn filter_frames(frames: &[Frame],
format: PrintFormat,
context: &BacktraceContext) -> (usize, usize)
{ {
(0, 0) if format == PrintFormat::Full {
return (0, 0);
}
let skipped_before = 0;
let skipped_after = frames.len() - frames.iter().position(|frame| {
let mut is_marker = false;
let _ = resolve_symname(*frame, |symname| {
if let Some(mangled_symbol_name) = symname {
// Use grep to find the concerned functions
if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
is_marker = true;
}
}
Ok(())
}, context);
is_marker
}).unwrap_or(frames.len());
if skipped_before + skipped_after >= frames.len() {
// Avoid showing completely empty backtraces
return (0, 0);
}
(skipped_before, skipped_after)
}
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
{
f()
} }
/// Controls how the backtrace should be formated. /// Controls how the backtrace should be formated.

View file

@ -358,7 +358,9 @@ impl Builder {
} }
unsafe { unsafe {
thread_info::set(imp::guard::current(), their_thread); thread_info::set(imp::guard::current(), their_thread);
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
::sys_common::backtrace::__rust_begin_short_backtrace(f)
}));
*their_packet.get() = Some(try_result); *their_packet.get() = Some(try_result);
} }
}; };

View file

@ -1314,12 +1314,16 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
let testfn = match x.testfn { let testfn = match x.testfn {
DynBenchFn(bench) => { DynBenchFn(bench) => {
DynTestFn(Box::new(move |()| { DynTestFn(Box::new(move |()| {
bench::run_once(|b| bench.run(b)) bench::run_once(|b| {
__rust_begin_short_backtrace(|| bench.run(b))
})
})) }))
} }
StaticBenchFn(benchfn) => { StaticBenchFn(benchfn) => {
DynTestFn(Box::new(move |()| { DynTestFn(Box::new(move |()| {
bench::run_once(|b| benchfn(b)) bench::run_once(|b| {
__rust_begin_short_backtrace(|| benchfn(b))
})
})) }))
} }
f => f, f => f,
@ -1425,12 +1429,24 @@ pub fn run_test(opts: &TestOpts,
monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap(); monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap();
return; return;
} }
DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f), DynTestFn(f) => {
StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, let cb = move |()| {
Box::new(move |()| f())), __rust_begin_short_backtrace(|| f.call_box(()))
};
run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb))
}
StaticTestFn(f) =>
run_test_inner(desc, monitor_ch, opts.nocapture,
Box::new(move |()| __rust_begin_short_backtrace(f))),
} }
} }
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
f()
}
fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> TestResult { fn calc_result(desc: &TestDesc, task_result: Result<(), Box<Any + Send>>) -> TestResult {
match (&desc.should_panic, task_result) { match (&desc.should_panic, task_result) {
(&ShouldPanic::No, Ok(())) | (&ShouldPanic::No, Ok(())) |