diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 78d5aa597ba0d..792bdd31e93be 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 99297b781e443..1c9c94becf921 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -93,6 +93,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { Ok(()) } +/// 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) @@ -101,59 +103,33 @@ fn filter_frames(frames: &[Frame], return (0, 0); } - // We want to filter out frames with some prefixes - // from both top and bottom of the call stack. + // Frames to remove from the top of the backtrace. + // + // The raw form is used so that we don't have to demangle the symbol names. + // The `a::b::c` form can show up on Windows/MSVC. static BAD_PREFIXES_TOP: &'static [&'static str] = &[ - "_ZN3std3sys3imp9backtrace", - "ZN3std3sys3imp9backtrace", "std::sys::imp::backtrace", - "_ZN3std10sys_common9backtrace", - "ZN3std10sys_common9backtrace", + "ZN3std3sys3imp9backtrace", + "std::sys_common::backtrace", - "_ZN3std9panicking", - "ZN3std9panicking", + "ZN3std10sys_common9backtrace", + "std::panicking", - "_ZN4core9panicking", - "ZN4core9panicking", + "ZN3std9panicking", + "core::panicking", - "_ZN4core6result13unwrap_failed", - "ZN4core6result13unwrap_failed", + "ZN4core9panicking", + "core::result::unwrap_failed", + "ZN4core6result13unwrap_failed", + "rust_begin_unwind", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", - ]; - static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[ - "_ZN3std9panicking", - "ZN3std9panicking", - "std::panicking", - "_ZN3std5panic", - "ZN3std5panic", - "std::panic", - "_ZN4core9panicking", - "ZN4core9panicking", - "core::panicking", - "_ZN3std2rt10lang_start", - "ZN3std2rt10lang_start", - "std::rt::lang_start", - "panic_unwind::__rust_maybe_catch_panic", - "__rust_maybe_catch_panic", - "_rust_maybe_catch_panic", - "__libc_start_main", - "__rust_try", - "_start", - "main", - "BaseThreadInitThunk", - "RtlInitializeExceptionChain", - "__scrt_common_main_seh", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", ]; let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| { resolve_symname(frame, |symname| { if let Some(mangled_symbol_name) = symname { - if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) { + if !bad_prefixes.iter().any(|s| mangled_symbol_name.contains(s)) { return Ok(()) } } @@ -164,11 +140,22 @@ fn filter_frames(frames: &[Frame], let skipped_before = frames.iter().position(|frame| { is_good_frame(*frame, BAD_PREFIXES_TOP) }).unwrap_or(frames.len()); - let skipped_after = frames[skipped_before..].iter().rev().position(|frame| { - is_good_frame(*frame, BAD_PREFIXES_BOTTOM) - }).unwrap_or(frames.len() - skipped_before); - if skipped_before + skipped_after == frames.len() { + 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); } @@ -176,6 +163,15 @@ fn filter_frames(frames: &[Frame], (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. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { @@ -198,7 +194,7 @@ pub fn log_enabled() -> Option { } let val = match env::var_os("RUST_BACKTRACE") { - Some(x) => if &x == "0" { + Some(x) => if &x == "0" || &x == "" { None } else if &x == "full" { Some(PrintFormat::Full) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 2bc066d3fea55..5d4f1e5b0c90d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -357,7 +357,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 5fdb0aa0641a0..54166325422f3 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1252,12 +1252,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_dyn(&bench, b) + }) })) } StaticBenchFn(benchfn) => { DynTestFn(Box::new(move |()| { - bench::run_once(|b| benchfn(b)) + bench::run_once(|b| { + __rust_begin_short_backtrace_bench_static(benchfn, b) + }) })) } f => f, @@ -1363,12 +1367,39 @@ 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) => + run_test_inner(desc, monitor_ch, opts.nocapture, + Box::new(move |()| __rust_begin_short_backtrace_test_boxfn(f))), + StaticTestFn(f) => + run_test_inner(desc, monitor_ch, opts.nocapture, + Box::new(move |()| __rust_begin_short_backtrace_test(f))), } } +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace_test_boxfn(f: Box>) { + f.call_box(()) +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace_test(f: fn()) { + f() +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace_bench_static(f: fn(&mut Bencher), b: &mut Bencher) { + f(b) +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace_bench_dyn(bench: &Box, b: &mut Bencher) { + bench.run(b) +} + fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) |