5 // FIXME: shouldn't ignore this test on i686-msvc, unsure why it's failing
6 #[cfg_attr(all(target_arch = "x86", target_env = "msvc"), ignore)]
7 #[rustfmt::skip] // we care about line numbers here
8 fn smoke_test_frames() {
10 #[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) }
11 #[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) }
12 #[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) }
13 #[inline(never)] fn frame_4(start_line: u32) {
14 let mut v
= Vec
::new();
15 backtrace
::trace(|cx
| {
20 // Various platforms have various bits of weirdness about their
21 // backtraces. To find a good starting spot let's search through the
23 let target
= frame_4
as usize;
26 .map(|frame
| frame
.symbol_address() as usize)
28 .filter_map(|(i
, sym
)| {
38 let mut frames
= v
[offset
..].iter();
41 frames
.next().unwrap(),
49 frames
.next().unwrap(),
57 frames
.next().unwrap(),
65 frames
.next().unwrap(),
73 frames
.next().unwrap(),
74 smoke_test_frames
as usize,
84 actual_fn_pointer
: usize,
90 backtrace
::resolve_frame(frame
, |sym
| {
91 print
!("symbol ip:{:?} address:{:?} ", frame
.ip(), frame
.symbol_address());
92 if let Some(name
) = sym
.name() {
93 print
!("name:{} ", name
);
95 if let Some(file
) = sym
.filename() {
96 print
!("file:{} ", file
.display());
98 if let Some(lineno
) = sym
.lineno() {
99 print
!("lineno:{} ", lineno
);
101 if let Some(colno
) = sym
.colno() {
102 print
!("colno:{} ", colno
);
107 let ip
= frame
.ip() as usize;
108 let sym
= frame
.symbol_address() as usize;
111 sym
>= actual_fn_pointer
,
112 "{:?} < {:?} ({} {}:{}:{})",
114 actual_fn_pointer
as *const usize,
121 // windows dbghelp is *quite* liberal (and wrong) in many of its reports
124 // This assertion can also fail for release builds, so skip it there
125 if cfg
!(debug_assertions
) {
126 assert
!(sym
- actual_fn_pointer
< 1024);
129 let mut resolved
= 0;
136 backtrace
::resolve_frame(frame
, |sym
| {
138 name
= sym
.name().map(|v
| v
.to_string());
142 file
= sym
.filename().map(|v
| v
.to_path_buf());
144 assert
!(resolved
> 0);
146 let name
= name
.expect("didn't find a name");
148 // in release mode names get weird as functions can get merged
149 // together with `mergefunc`, so only assert this in debug mode
150 if cfg
!(debug_assertions
) {
152 name
.contains(expected_name
),
153 "didn't find `{}` in `{}`",
159 addr
.expect("didn't find a symbol");
161 if cfg
!(debug_assertions
) {
162 let line
= line
.expect("didn't find a line number");
163 let file
= file
.expect("didn't find a line number");
164 if !expected_file
.is_empty() {
166 file
.ends_with(expected_file
),
167 "{:?} didn't end with {:?}",
172 if expected_line
!= 0 {
174 line
== expected_line
,
175 "bad line number on frame for `{}`: {} != {}",
182 // dbghelp on MSVC doesn't support column numbers
183 if !cfg
!(target_env
= "msvc") {
184 let col
= col
.expect("didn't find a column number");
185 if expected_col
!= 0 {
188 "bad column number on frame for `{}`: {} != {}",
201 let threads
= (0..16)
205 backtrace
::trace(|frame
| {
206 backtrace
::resolve(frame
.ip(), |symbol
| {
207 let _s
= symbol
.name().map(|s
| s
.to_string());
214 .collect
::<Vec
<_
>>();
222 #[cfg(feature = "rustc-serialize")]
223 fn is_rustc_serialize() {
224 extern crate rustc_serialize
;
226 fn is_encode
<T
: rustc_serialize
::Encodable
>() {}
227 fn is_decode
<T
: rustc_serialize
::Decodable
>() {}
229 is_encode
::<backtrace
::Backtrace
>();
230 is_decode
::<backtrace
::Backtrace
>();
234 #[cfg(feature = "serde")]
238 fn is_serialize
<T
: serde
::ser
::Serialize
>() {}
239 fn is_deserialize
<T
: serde
::de
::DeserializeOwned
>() {}
241 is_serialize
::<backtrace
::Backtrace
>();
242 is_deserialize
::<backtrace
::Backtrace
>();
247 let mut refs
= vec
![];
248 recursive_stack_references(&mut refs
);
252 fn recursive_stack_references(refs
: &mut Vec
<usize>) {
253 assert
!(refs
.len() < 5);
256 refs
.push(&x
as *const _
as usize);
259 recursive_stack_references(refs
);
260 eprintln
!("exiting: {}", x
);
264 backtrace
::trace(make_trace_closure(refs
));
265 eprintln
!("exiting: {}", x
);
268 // NB: the following `make_*` functions are pulled out of line, rather than
269 // defining their results as inline closures at their call sites, so that
270 // the resulting closures don't have "recursive_stack_references" in their
273 fn make_trace_closure
<'a
>(
274 refs
: &'a
mut Vec
<usize>,
275 ) -> impl FnMut(&backtrace
::Frame
) -> bool
+ 'a
{
276 let mut child_sp
= None
;
277 let mut child_ref
= None
;
279 eprintln
!("\n=== frame ===================================");
281 let mut is_recursive_stack_references
= false;
282 backtrace
::resolve(frame
.ip(), |sym
| {
283 is_recursive_stack_references
|=
285 .and_then(|name
| name
.as_str())
286 .map_or(false, |name
| {
287 eprintln
!("name = {}", name
);
288 name
.contains("recursive_stack_references")
292 let sp
= frame
.sp() as usize;
293 eprintln
!("sp = {:p}", sp
as *const u8);
295 // If the SP is null, then we don't have an implementation for
296 // getting the SP on this target. Just keep walking the stack,
297 // but don't make our assertions about the on-stack pointers and
302 // The stack grows down.
303 if let Some(child_sp
) = child_sp
{
304 assert
!(child_sp
<= sp
);
307 if is_recursive_stack_references
{
308 let r
= refs
.pop().unwrap();
309 eprintln
!("ref = {:p}", r
as *const u8);
312 if let Some(child_ref
) = child_ref
{
313 assert
!(sp
>= child_ref
);