Skip to content

Ignore functions before main and thread entry points in backtraces #49825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/libstd/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
// Re-export some of our utilities which are expected by other crates.
pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count};

#[cfg(feature = "backtrace")]
pub use sys_common::backtrace::begin_short_backtrace;

#[cfg(not(feature = "backtrace"))]
#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")]
pub fn begin_short_backtrace<F: FnOnce() -> R, R>(f: F) -> R {
f()
}

// To reduce the generated code of the new `lang_start`, this function is doing
// the real work.
#[cfg(not(test))]
Expand Down Expand Up @@ -56,7 +65,7 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe),
// Let's run some code!
#[cfg(feature = "backtrace")]
let exit_code = panic::catch_unwind(|| {
::sys_common::backtrace::__rust_begin_short_backtrace(move || main())
::sys_common::backtrace::begin_short_backtrace(move || main())
});
#[cfg(not(feature = "backtrace"))]
let exit_code = panic::catch_unwind(move || main());
Expand Down
8 changes: 4 additions & 4 deletions src/libstd/sys/cloudabi/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,17 @@ where

pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>,
F: FnOnce(Option<(&str, usize)>) -> io::Result<()>,
{
unsafe {
let mut info: Dl_info = intrinsics::init();
let symname =
let syminfo =
if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() {
None
} else {
CStr::from_ptr(info.dli_sname).to_str().ok()
CStr::from_ptr(info.dli_sname).to_str().ok().map(|s| (s, info.dli_saddr as usize))
};
callback(symname)
callback(syminfo)
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/libstd/sys/unix/backtrace/printing/dladdr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ use sys_common::backtrace::Frame;
pub fn resolve_symname<F>(frame: Frame,
callback: F,
_: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
{
unsafe {
let mut info: Dl_info = intrinsics::init();
let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
let syminfo = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
info.dli_sname.is_null() {
None
} else {
CStr::from_ptr(info.dli_sname).to_str().ok()
CStr::from_ptr(info.dli_sname).to_str().ok().map(|s| (s, info.dli_saddr as usize))
};
callback(symname)
callback(syminfo)
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/libstd/sys/unix/backtrace/printing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline;
#[cfg(not(target_os = "emscripten"))]
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>
F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
{
::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
if symname.is_some() {
callback(symname)
::sys_common::gnu::libbacktrace::resolve_symname(frame, |syminfo| {
if syminfo.is_some() {
callback(syminfo)
} else {
dladdr::resolve_symname(frame, callback, bc)
}
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/sys/wasm/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn unwind_backtrace(_frames: &mut [Frame])
pub fn resolve_symname<F>(_frame: Frame,
_callback: F,
_: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
{
unsupported()
}
Expand Down
10 changes: 6 additions & 4 deletions src/libstd/sys/windows/backtrace/printing/msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type SymGetLineFromInlineContextFn =
pub fn resolve_symname<F>(frame: Frame,
callback: F,
context: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
{
let SymFromInlineContext = sym!(&context.dbghelp,
"SymFromInlineContext",
Expand Down Expand Up @@ -57,13 +57,15 @@ pub fn resolve_symname<F>(frame: Frame,
} else {
false
};
let symname = if valid_range {
let syminfo = if valid_range {
let ptr = info.Name.as_ptr() as *const c_char;
CStr::from_ptr(ptr).to_str().ok()
CStr::from_ptr(ptr).to_str().ok().map(|s| {
(s, (frame.symbol_addr as usize).wrapping_sub(displacement as usize))
})
} else {
None
};
callback(symname)
callback(syminfo)
}
}

Expand Down
41 changes: 28 additions & 13 deletions src/libstd/sys_common/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {

let filtered_frames = &frames[..nb_frames - skipped_after];
for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
resolve_symname(*frame, |symname| {
output(w, index, *frame, symname, format)
resolve_symname(*frame, |syminfo| {
output(w, index, *frame, syminfo.map(|i| i.0), format)
}, &context)?;
let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
output_fileline(w, file, line, format)
Expand All @@ -105,14 +105,14 @@ fn filter_frames(frames: &[Frame],

let skipped_before = 0;

// Look for the first occurence of `mark_start`
// There can be multiple in one backtrace
// Skip all frames after that
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;
}
let _ = resolve_symname(*frame, |syminfo| {
if syminfo.map(|i| i.1) == Some(MARK_START as usize) {
is_marker = true;
}
Ok(())
}, context);
Expand All @@ -127,13 +127,28 @@ fn filter_frames(frames: &[Frame],
(skipped_before, skipped_after)
}

static MARK_START: fn(&mut FnMut()) = mark_start;

/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
/// 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, T: Send
{
f()
fn mark_start(f: &mut FnMut()) {
f();
#[cfg(not(target_arch = "asmjs"))]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now just excludes asmjs from the changes.

unsafe {
asm!("" ::: "memory" : "volatile"); // A dummy statement to prevent tail call optimization
}
}

/// Convenience wrapper for `mark_start`
#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")]
pub fn begin_short_backtrace<F: FnOnce() -> R, R>(f: F) -> R {
let mut f = Some(f);
let mut r = None;
mark_start(&mut || {
let f = f.take().unwrap();
r = Some(f());
});
r.unwrap()
}

/// Controls how the backtrace should be formatted.
Expand Down
20 changes: 10 additions & 10 deletions src/libstd/sys_common/gnu/libbacktrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,34 @@ where F: FnMut(&[u8], u32) -> io::Result<()>
pub fn resolve_symname<F>(frame: Frame,
callback: F,
_: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
{
let symname = {
let syminfo = {
let state = unsafe { init_state() };
if state.is_null() {
return Err(io::Error::new(
io::ErrorKind::Other,
"failed to allocate libbacktrace state")
)
}
let mut data: *const libc::c_char = ptr::null();
let data_addr = &mut data as *mut *const libc::c_char;
let mut data: (*const libc::c_char, _) = (ptr::null(), 0);
let data_addr = &mut data as *mut _;
let ret = unsafe {
backtrace_syminfo(state,
frame.symbol_addr as libc::uintptr_t,
syminfo_cb,
error_cb,
data_addr as *mut libc::c_void)
};
if ret == 0 || data.is_null() {
if ret == 0 || data.0.is_null() {
None
} else {
unsafe {
CStr::from_ptr(data).to_str().ok()
CStr::from_ptr(data.0).to_str().ok().map(|s| (s, data.1))
}
}
};
callback(symname)
callback(syminfo)
}

////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -145,10 +145,10 @@ extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
extern fn syminfo_cb(data: *mut libc::c_void,
_pc: libc::uintptr_t,
symname: *const libc::c_char,
_symval: libc::uintptr_t,
symval: libc::uintptr_t,
_symsize: libc::uintptr_t) {
let slot = data as *mut *const libc::c_char;
unsafe { *slot = symname; }
let slot = data as *mut (*const libc::c_char, usize);
unsafe { *slot = (symname, symval); }
}
extern fn pcinfo_cb(data: *mut libc::c_void,
_pc: libc::uintptr_t,
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ impl Builder {
thread_info::set(imp::guard::current(), their_thread);
#[cfg(feature = "backtrace")]
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
::sys_common::backtrace::__rust_begin_short_backtrace(f)
::sys_common::backtrace::begin_short_backtrace(f)
}));
#[cfg(not(feature = "backtrace"))]
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
Expand Down
16 changes: 6 additions & 10 deletions src/libtest/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(termination_trait_lib)]
#![feature(rt)]

extern crate getopts;
#[cfg(any(unix, target_os = "cloudabi"))]
Expand Down Expand Up @@ -73,6 +74,7 @@ use std::thread;
use std::time::{Duration, Instant};
use std::borrow::Cow;
use std::process;
use std::rt::begin_short_backtrace;

const TEST_WARN_TIMEOUT_S: u64 = 60;
const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
Expand Down Expand Up @@ -1353,10 +1355,10 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
.map(|x| {
let testfn = match x.testfn {
DynBenchFn(bench) => DynTestFn(Box::new(move || {
bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b)))
bench::run_once(|b| begin_short_backtrace(|| bench.run(b)))
})),
StaticBenchFn(benchfn) => DynTestFn(Box::new(move || {
bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
bench::run_once(|b| begin_short_backtrace(|| benchfn(b)))
})),
f => f,
};
Expand Down Expand Up @@ -1443,24 +1445,18 @@ pub fn run_test(
});
}
DynTestFn(f) => {
let cb = move || __rust_begin_short_backtrace(f);
let cb = move || begin_short_backtrace(f);
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)),
Box::new(move || 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 {
match (&desc.should_panic, task_result) {
(&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
Expand Down