-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Ignore more frames on backtrace unwinding. #40264
Conversation
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. Fixes rust-lang#40201
(rust_highfive has picked a reviewer for you, use r? to override) |
This may be troublesome due to |
Yeah, I fixed that in the latest commit ;) First post updated. |
Some thoughts:
|
src/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" { |
There was a problem hiding this comment.
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).
|
C-calling-rust works as expected, all the C frames are kept. |
@Yamakaky |
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 |
There was a problem hiding this comment.
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....
src/libstd/sys_common/backtrace.rs
Outdated
"_ZN4core6result13unwrap_failed", | ||
"ZN4core6result13unwrap_failed", | ||
"core::result::unwrap_failed", | ||
|
||
"rust_begin_unwind", | ||
"_ZN4drop", |
There was a problem hiding this comment.
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?
src/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", |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
src/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", |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
The frames in
it will only remove A and not D. I can remove the special handling of |
I don't think that's the problem though, if the stack trace as B/C/D/E we'd remove everything but E? |
if |
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. |
src/libstd/sys_common/backtrace.rs
Outdated
"__rust_maybe_catch_panic", | ||
"_rust_maybe_catch_panic", | ||
"__libc_start_main", | ||
|
||
"__rust_try", |
There was a problem hiding this comment.
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.
src/libstd/sys_common/backtrace.rs
Outdated
|
||
"_ZN4core3ops6FnOnce9call_once", | ||
"ZN4core3ops6FnOnce9call_once", | ||
"core::ops::FnOnce::call_once", |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Like for this backtrace (rustc without optimisations), what would you want to remove?
|
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. |
Same question with explicit panic catch (the last example in my first post) https://gist.github.com/Yamakaky/b4c5168b8478311f66b02d47013f7cf1 |
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. |
That's exactly what the current code does ;) |
src/libstd/sys_common/backtrace.rs
Outdated
"core::result::unwrap_failed", | ||
"ZN4core6result13unwrap_failed", | ||
|
||
"rust_begin_unwind", | ||
"_ZN4drop", | ||
"mingw_set_invalid_parameter_handler", |
There was a problem hiding this comment.
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
// 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] = &[ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
@Yamakaky any update on removing the large lists of whitelists to canonical frames to prune? |
No, sorry. I'm near the end of the school semester so I have a lot of things to do. |
No worries! Thanks for the update. |
Ping @Yamakaky - are you still working on this PR? |
Not now, I still have a week before the end of the semester. You can work on it if you want! |
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.
…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.
…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.
☔ The latest upstream changes (presumably #41373) made this pull request unmergeable. Please resolve the merge conflicts. |
Ok I'm going to close this for now, but please feel free to resubmit @Yamakaky if you find the time! |
Is it OK if I open a PR with only the bottom cleaning, and leave the top for a later PR? |
Certainly! |
…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.
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.
@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. |
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.Any idea about use-cases I would have forgotten?