From ca8b75466cef854d30fdf7614c2358b1eb46816e Mon Sep 17 00:00:00 2001 From: Yamakaky Date: Sat, 4 Mar 2017 10:27:52 -0500 Subject: [PATCH] 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 --- src/libstd/rt.rs | 7 +++-- src/libstd/sys_common/backtrace.rs | 44 +++++++++++++++++++++++++++--- src/libstd/thread/mod.rs | 4 ++- src/libtest/lib.rs | 26 ++++++++++++++---- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 6c791cd336ded..acff7faf8a7d0 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -29,8 +29,7 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; #[cfg(not(test))] #[lang = "start"] -fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { - use mem; +fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize { use panic; use sys; 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); // 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(); res.is_err() }; diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 04fe5f78b03ce..617218fe7a5a6 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -93,11 +93,47 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { Ok(()) } -fn filter_frames(_frames: &[Frame], - _format: PrintFormat, - _context: &BacktraceContext) -> (usize, usize) +/// Returns a number of frames to remove at the beginning and at the end of the +/// backtrace, according to the backtrace format. +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: F) -> T + where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static +{ + f() } /// Controls how the backtrace should be formated. diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 04cd28df4459d..3101d08244e31 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -358,7 +358,9 @@ impl Builder { } unsafe { 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); } }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 35f2fbca69f8d..0d615db3deb47 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1314,12 +1314,16 @@ pub fn convert_benchmarks_to_tests(tests: Vec) -> Vec { DynTestFn(Box::new(move |()| { - bench::run_once(|b| bench.run(b)) + bench::run_once(|b| { + __rust_begin_short_backtrace(|| bench.run(b)) + }) })) } StaticBenchFn(benchfn) => { DynTestFn(Box::new(move |()| { - bench::run_once(|b| benchfn(b)) + bench::run_once(|b| { + __rust_begin_short_backtrace(|| benchfn(b)) + }) })) } f => f, @@ -1425,12 +1429,24 @@ pub fn run_test(opts: &TestOpts, monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap(); return; } - DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f), - StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, - Box::new(move |()| f())), + DynTestFn(f) => { + let cb = move |()| { + __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: F) { + f() +} + fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) |