Skip to content

Commit 2e1d85f

Browse files
committed
Include -1 logic on Unix for libbacktrace
After tweaking where all the `-1` annotations are located this is hopefully the final central location they need to be in... In any case this also imports the test from libstd which is typically failing upstream so we can get earlier signals to failures here.
1 parent ae32ffc commit 2e1d85f

File tree

4 files changed

+126
-9
lines changed

4 files changed

+126
-9
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,8 @@ required-features = ["std"]
143143
name = "smoke"
144144
required-features = ["std"]
145145
edition = '2018'
146+
147+
[[test]]
148+
name = "accuracy"
149+
required-features = ["std", "dbghelp", "libbacktrace", "libunwind"]
150+
edition = '2018'

src/symbolize/libbacktrace.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -413,15 +413,20 @@ unsafe fn init_state() -> *mut bt::backtrace_state {
413413
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
414414
let mut symaddr = what.address_or_ip() as usize;
415415

416-
// It's sort of unclear why this is necessary, but it appears that the ip
417-
// values from stack traces are typically the instruction *after* the call
418-
// that's the actual stack trace. Symbolizing this on Windows causes the
419-
// filename/line number to be one ahead and perhaps into the void if it's
420-
// near the end of the function. Apparently on Unix though it's roughly fine
421-
// in that the filename/line number turn out alright. For now just try to
422-
// get good backtraces with this, and hopefully one day we can figure out
423-
// why the `-=1` is here.
424-
if cfg!(windows) && symaddr > 0 {
416+
// IP values from stack frames are typically (always?) the instruction
417+
// *after* the call that's the actual stack trace. Symbolizing this on
418+
// causes the filename/line number to be one ahead and perhaps into
419+
// the void if it's near the end of the function.
420+
//
421+
// On Windows it's pretty sure that it's always the case that the IP is one
422+
// ahead (except for the final frame but oh well) and for Unix it appears
423+
// that we used to use `_Unwind_GetIPInfo` which tells us if the instruction
424+
// is the next or not, but it seems that on all platforms it's always the
425+
// next instruction so far so let's just always assume that.
426+
//
427+
// In any case we'll probably have to tweak this over time, but for now this
428+
// gives the most accurate backtraces.
429+
if symaddr > 0 {
425430
symaddr -= 1;
426431
}
427432

tests/accuracy/aux.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[inline(never)]
2+
pub fn callback<F>(f: F) where F: FnOnce((&'static str, u32)) {
3+
f((file!(), line!()))
4+
}
5+
6+
// We emit the wrong location for the caller here when inlined on MSVC
7+
#[cfg_attr(not(target_env = "msvc"), inline(always))]
8+
#[cfg_attr(target_env = "msvc", inline(never))]
9+
pub fn callback_inlined<F>(f: F) where F: FnOnce((&'static str, u32)) {
10+
f((file!(), line!()))
11+
}

tests/accuracy/main.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use std::path::Path;
2+
3+
mod aux;
4+
5+
macro_rules! pos {
6+
() => {
7+
(file!(), line!())
8+
};
9+
}
10+
11+
macro_rules! check {
12+
($($pos:expr),*) => ({
13+
verify(&[$($pos),*]);
14+
})
15+
}
16+
17+
type Pos = (&'static str, u32);
18+
19+
#[test]
20+
fn doit() {
21+
outer(pos!());
22+
}
23+
24+
#[inline(never)]
25+
fn outer(main_pos: Pos) {
26+
inner(main_pos, pos!());
27+
inner_inlined(main_pos, pos!());
28+
}
29+
30+
#[inline(never)]
31+
#[rustfmt::skip]
32+
fn inner(main_pos: Pos, outer_pos: Pos) {
33+
check!(main_pos, outer_pos);
34+
check!(main_pos, outer_pos);
35+
let inner_pos = pos!(); aux::callback(|aux_pos| {
36+
check!(main_pos, outer_pos, inner_pos, aux_pos);
37+
});
38+
let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
39+
check!(main_pos, outer_pos, inner_pos, aux_pos);
40+
});
41+
}
42+
43+
// We emit the wrong location for the caller here when inlined on MSVC
44+
#[cfg_attr(not(target_env = "msvc"), inline(always))]
45+
#[cfg_attr(target_env = "msvc", inline(never))]
46+
#[rustfmt::skip]
47+
fn inner_inlined(main_pos: Pos, outer_pos: Pos) {
48+
check!(main_pos, outer_pos);
49+
check!(main_pos, outer_pos);
50+
51+
// Again, disable inlining for MSVC.
52+
#[cfg_attr(not(target_env = "msvc"), inline(always))]
53+
#[cfg_attr(target_env = "msvc", inline(never))]
54+
fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) {
55+
check!(main_pos, outer_pos, inner_pos);
56+
}
57+
inner_further_inlined(main_pos, outer_pos, pos!());
58+
59+
let inner_pos = pos!(); aux::callback(|aux_pos| {
60+
check!(main_pos, outer_pos, inner_pos, aux_pos);
61+
});
62+
let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
63+
check!(main_pos, outer_pos, inner_pos, aux_pos);
64+
});
65+
66+
// this tests a distinction between two independent calls to the inlined function.
67+
// (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
68+
inner_further_inlined(main_pos, outer_pos, pos!());
69+
}
70+
71+
fn verify(filelines: &[Pos]) {
72+
let trace = backtrace::Backtrace::new();
73+
println!("-----------------------------------");
74+
println!("looking for:");
75+
for (file, line) in filelines.iter().rev() {
76+
println!("\t{}:{}", file, line);
77+
}
78+
println!("found:\n{:?}", trace);
79+
let mut symbols = trace.frames().iter().flat_map(|frame| frame.symbols());
80+
let mut iter = filelines.iter().rev();
81+
while let Some((file, line)) = iter.next() {
82+
loop {
83+
let sym = match symbols.next() {
84+
Some(sym) => sym,
85+
None => panic!("failed to find {}:{}", file, line),
86+
};
87+
if let Some(filename) = sym.filename() {
88+
if let Some(lineno) = sym.lineno() {
89+
if filename == Path::new(file) && lineno == *line {
90+
break;
91+
}
92+
}
93+
}
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)