Skip to content

Ignore more frames on backtrace unwinding. - #40264

Closed
Yamakaky wants to merge 17 commits into
rust-lang:masterfrom
Yamakaky:improve-backtrace
Closed

Ignore more frames on backtrace unwinding.#40264
Yamakaky wants to merge 17 commits into
rust-lang:masterfrom
Yamakaky:improve-backtrace

Conversation

@Yamakaky

@YamakakyYamakaky commented Mar 4, 2017

Copy link
Copy Markdown
Contributor

Correctly handles panics in threads and tests. First, the frames after the last __rust_maybe_catch_panic are discarded, then it uses a blacklist that does some more fine-tuning. Since frames after the call to __rust_maybe_catch_panic seem to be platform-independant, BAD_PREFIXES_BOTTOM could probably be cleaned a bit.

#[test]fnb(){None::<()>.unwrap();}
 0: <core::option::Option<T>>::unwrap
at /home/yamakaky/dev/rust/rust/src/libcore/macros.rs:21
1: t::b
at ./t.rs:12
fnmain(){::std::thread::spawn(|| panic!()).join().unwrap();}
 0: t::main::{{closure}}
at ./t.rs:2
...
0: <core::result::Result<T, E>>::unwrap
at /home/yamakaky/dev/rust/rust/src/libcore/result.rs:737
1: t::main
at ./t.rs:2
fnmain(){let result = ::std::panic::catch_unwind(|| {panic!("oh no!");});assert!(result.is_err());}
 0: t::main::{{closure}}
at ./t.rs:10
1: std::panicking::try::do_call
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:454
2: __rust_try
3: __rust_maybe_catch_panic
at /home/yamakaky/dev/rust/rust/src/libpanic_unwind/lib.rs:98
4: std::panicking::try
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:433
5: std::panic::catch_unwind
at /home/yamakaky/dev/rust/rust/src/libstd/panic.rs:361
6: t::main
at ./t.rs:9

Any idea about use-cases I would have forgotten?

Correctly handles panics in threads and tests. First, the frames after
`__rust_maybe_catch_panic` are discarded, then it uses a blacklist that
does some more fine-tuning. Since frames after the call to
`__rust_maybe_catch_panic` seem to be platform-independant,
`BAD_PREFIXES_BOTTOM` could probably be cleaned a bit.
Fixesrust-lang#40201
@rust-highfive

Copy link
Copy Markdown
Contributor

r? @alexcrichton

(rust_highfive has picked a reviewer for you, use r? to override)

@nagisa

Copy link
Copy Markdown
Member

First, the frames after __rust_maybe_catch_panic are discarded

This may be troublesome due to std::panic::catch_unwind which calls this function as well.

@Yamakaky

Yamakaky commented Mar 4, 2017

Copy link
Copy Markdown
ContributorAuthor

Yeah, I fixed that in the latest commit ;) First post updated.

@petrochenkov

petrochenkov commented Mar 4, 2017

Copy link
Copy Markdown
Contributor

Some thoughts:

  • no_std programs don't have rust_maybe_catch_panic D'oh.
  • dropping frames at thread boundary doesn't seem good. I was pretty sure I've seen backtraces spanning across thread boundaries with gdb and C code, but that doesn't seem to be true.
  • rust_maybe_catch_panic is called as a part of usual catch_unwind, e.g. at boundaries with C libraries, for example. dropping frames from C libraries doesn't seem good as well.

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated
let mut is_rmcp = false;
let _ = resolve_symname(*frame, |symname| {
if let Some(mangled_symbol_name) = symname {
if mangled_symbol_name == "__rust_maybe_catch_panic" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs to be mangled_symbol_name.contains("rust_maybe_catch_panic") (regardless of other concerns) because the symbol can be named panic_unwind::__rust_maybe_catch_panic or _rust_maybe_catch_panic (on Windows).

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

C-calling-rust works as expected, all the C frames are kept.

@petrochenkov

Copy link
Copy Markdown
Contributor

@Yamakaky
I meant C calling Rust wrapped into catch_unwind, not just C calling Rust.

@Yamakaky

Yamakaky commented Mar 4, 2017

Copy link
Copy Markdown
ContributorAuthor

Hum, right. Is it possible to detect if the current crate is a .so or .a?

Also, I'm not sure it's that bad. It's a very specific use case, and we can't clean the C backtrace so it would have the same bottom frames than RUST_BACKTRACE=full. On the other hand, we gain robustness against all the different frame setups on the supported platforms.

@alexcrichtonalexcrichton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm getting slightly worried about how aggressively we're trying to hide frames while yet having a desire for this to be general purpose. It looks like we're already dropping frames that are otherwise valid and this continues to be very light on tests....

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated
"core::result::unwrap_failed",

"rust_begin_unwind",
"_ZN4drop",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Er was this added in the previous PR? This definitely seems like something that we shouldn't be dropping, this is just a normal function?

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated
$LT$$LP$$RP$$GT$$GT$9call_once",
"ZN91_$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..FnOnce\
$LT$$LP$$RP$$GT$$GT$9call_once",
"<std::panic::AssertUnwindSafe<F> as core::ops::FnOnce<()>>::call_once",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think that these are correct to have because this is just the beginning of a catch_unwind, right?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So? It's std stuff, we want to remove it.

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated

"_ZN42_$LT$F$u20$as$u20$test..FnBox$LT$T$GT$$GT$8call_box",
"ZN42_$LT$F$u20$as$u20$test..FnBox$LT$T$GT$$GT$8call_box",
"<F as test::FnBox<T>>::call_box",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These can happen at any time, right? Not just during tests?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not sure, but it was fine during my tests.

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

The frames in BAD_PREFIXES_BOTTOM/TOP are only removed if all the frames before (resp. after) were removed. Like if BAD_PREFIXES_TOP = [A, D] and the stackframe is

A
B
C
D
E

it will only remove A and not D.

I can remove the special handling of __rust_maybe_catch_panic, but it will mean BAD_PREFIXES_BOTTOM will stay big, and with platform-specific function names in libstd/sys_common. If we revert it, then maybe split between the platform-specific frames and the common ones?

@alexcrichton

Copy link
Copy Markdown
Member

I don't think that's the problem though, if the stack trace as B/C/D/E we'd remove everything but E?

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

if BAD_PREFIXES_TOP = [A, D] and the stacktrace is B/C/D/E, then it's not modified.

@alexcrichton

Copy link
Copy Markdown
Member

Ok but the point still stands I think, can we be less aggressive about pruning frames? Many of these patterns are legitimate Rust functions not related to unwinding.

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated
"_rust_maybe_catch_panic",
"__libc_start_main",

"__rust_try",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think that we want this to be the bottom of a frame, this is just one panic::catch_unwind and there could be many on the stack.

Comment threadsrc/libstd/sys_common/backtrace.rs Outdated

"_ZN4core3ops6FnOnce9call_once",
"ZN4core3ops6FnOnce9call_once",
"core::ops::FnOnce::call_once",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Like above, these could be any rust function, so we shouldn't prune these

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I fail to find an example where this frame would be at the beginning of the frame and you would not want to remove it. There will always be the main, or a function if it's a library.

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

Like for this backtrace (rustc without optimisations), what would you want to remove?

thread 'main' panicked at 'explicit panic', t.rs:2
stack backtrace:
0: 0x562b31ac45f8 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::hf65740f571b3b062
at /home/yamakaky/dev/rust/rust/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: 0x562b31af430e - std::sys_common::backtrace::_print::h49fe0d471b73c20e
at /home/yamakaky/dev/rust/rust/src/libstd/sys_common/backtrace.rs:71
2: 0x562b31af351e - std::sys_common::backtrace::print::hd65a646efeb9e475
at /home/yamakaky/dev/rust/rust/src/libstd/sys_common/backtrace.rs:60
3: 0x562b31ac704e - std::panicking::default_hook::{{closure}}::h25191b25fd3a12b5
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:355
4: 0x562b31ac6b1c - std::panicking::default_hook::hf7e171cc5ec0b024
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:371
5: 0x562b31ac795c - std::panicking::rust_panic_with_hook::h01e0c787710839ce
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:549
6: 0x562b31ab5343 - std::panicking::begin_panic::h67ddf8e748228f4b
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:511
7: 0x562b31ab5852 - t::main::hf31397ea67eea730
at /tmp/t.rs:2
8: 0x562b31ac7e85 - core::ops::FnOnce::call_once::h97136135af0c9b86
9: 0x562b31ac737a - std::panicking::try::do_call::h0b3ba9923f346cc7
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:454
10: 0x562b31b08347 - __rust_try
11: 0x562b31b08227 - __rust_maybe_catch_panic
at /home/yamakaky/dev/rust/rust/src/libpanic_unwind/lib.rs:98
12: 0x562b31ac7167 - std::panicking::try::h2b94160ac273c42a
at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:433
13: 0x562b31adc66a - std::panic::catch_unwind::h8c1f7b1121d92ea1
at /home/yamakaky/dev/rust/rust/src/libstd/panic.rs:361
14: 0x562b31adf67e - std::rt::lang_start::h29d9bdfd34a5eab2
at /home/yamakaky/dev/rust/rust/src/libstd/rt.rs:57
15: 0x562b31ab5892 - main
16: 0x7feb00a57290 - __libc_start_main
17: 0x562b31ab5169 - _start
18: 0x0 - <unknown>

@alexcrichton

Copy link
Copy Markdown
Member

Ideally we'd only show frame 7 in that stack trace, but I think that we need to show 7-13 because we don't know if frames 8-13 are a nested catch panic or not.

I think we can safely assume though that frames 0-6 are panicking machinery which can be ignored by default. Similarly 14-18 are safely system frames.

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

Same question with explicit panic catch (the last example in my first post) https://gist.github.com/Yamakaky/b4c5168b8478311f66b02d47013f7cf1

@alexcrichton

Copy link
Copy Markdown
Member

Yes that should only strip frames 0-6 and 14-24 ideally as those weren't written by the user. I don't know of a heuristic which will actually do that though.

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

That's exactly what the current code does ;)

@alexcrichtonalexcrichton added the T-libs-api [DEPRECATED; DO NOT USE] label Mar 14, 2017
Comment threadsrc/libstd/sys_common/backtrace.rs Outdated

"rust_begin_unwind",
"_ZN4drop",
"mingw_set_invalid_parameter_handler",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This and drop above should be removed

//
// 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] = &[

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we remove this array entirely? Currently rust_panic is the "canonical frame name" of the panic, and if there's a lower frame we should start from then we should just give that a canonical name instead.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

What to you think about removing the frames from the core::panicking::panic* functions?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's fine to strive to eliminate them, but we shouldn't have such a long list of what to filter. There should be one frame that we look for and if we find it maybe do a few calculations based off that. Substring searching is basically guarantee to go wrong in the future.

@alexcrichton

Copy link
Copy Markdown
Member

@Yamakaky any update on removing the large lists of whitelists to canonical frames to prune?

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

No, sorry. I'm near the end of the school semester so I have a lot of things to do.

@alexcrichton

Copy link
Copy Markdown
Member

No worries! Thanks for the update.

@Mark-SimulacrumMark-Simulacrum added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Apr 14, 2017
@arielb1

Copy link
Copy Markdown
Contributor

Ping @Yamakaky - are you still working on this PR?

@arielb1arielb1 closed this Apr 18, 2017
@arielb1arielb1 reopened this Apr 18, 2017
@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

Not now, I still have a week before the end of the semester. You can work on it if you want!

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Apr 18, 2017
It was discovered rust-lang#40264 that this backtrace pruning logic is a little too
aggressive, so while we figure how out to handle rust-lang#40264 this commit backs out
the changes to prune frames. Note that other cosmetic changes, such as better
path printing and such remain.
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017
…r=petrochenkov
std: Back out backtrace pruning logic
It was discovered rust-lang#40264 that this backtrace pruning logic is a little too
aggressive, so while we figure how out to handle rust-lang#40264 this commit backs out
the changes to prune frames. Note that other cosmetic changes, such as better
path printing and such remain.
frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017
…r=petrochenkov
std: Back out backtrace pruning logic
It was discovered rust-lang#40264 that this backtrace pruning logic is a little too
aggressive, so while we figure how out to handle rust-lang#40264 this commit backs out
the changes to prune frames. Note that other cosmetic changes, such as better
path printing and such remain.
@bors

bors commented Apr 18, 2017

Copy link
Copy Markdown
Collaborator

☔ The latest upstream changes (presumably #41373) made this pull request unmergeable. Please resolve the merge conflicts.

@alexcrichton

Copy link
Copy Markdown
Member

Ok I'm going to close this for now, but please feel free to resubmit @Yamakaky if you find the time!

@Yamakaky

Copy link
Copy Markdown
ContributorAuthor

Is it OK if I open a PR with only the bottom cleaning, and leave the top for a later PR?

@alexcrichton

Copy link
Copy Markdown
Member

Certainly!

@Yamakaky
Yamakaky deleted the improve-backtrace branch May 7, 2017 17:40
frewsxcv added a commit to frewsxcv/rust that referenced this pull request May 10, 2017
…r=alexcrichton
Improve cleaning of the bottom of the backtrace
Following rust-lang#40264. It only cleans the bottom of the trace (after the main). It handles correctly the normal main, tests, benchmarks and threads.
I kept `skipped_before` since it will be used later for the cleaning of the top.
bors added a commit that referenced this pull request May 10, 2017
Improve cleaning of the bottom of the backtrace
Following #40264. It only cleans the bottom of the trace (after the main). It handles correctly the normal main, tests, benchmarks and threads.
I kept `skipped_before` since it will be used later for the cleaning of the top.
@whitequark

Copy link
Copy Markdown
Contributor

@Yamakaky Do you think you can take another look on this PR? It would be really great to say goodbye to all the junk in the backtraces.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-authorStatus: This is awaiting some action (such as code changes or more information) from the author.T-libs-api[DEPRECATED; DO NOT USE]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

12 participants

@Yamakaky@rust-highfive@nagisa@petrochenkov@alexcrichton@aturon@sfackler@ranma42@arielb1@bors@whitequark@Mark-Simulacrum