-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
matching on functions with similar call stacks breaks optimized backtraces even with debuginfo #134909
Comments
as far as i can tell, this is the main difference in llvm ir between the two (other than the missing debuginfo). left is the broken code, right is working.
note that the working code has probably some optimization pass that looks at |
the only use of |
The two unwrap calls get merged, so they will use the merged debug location. This fundamentally has to lose the information about which of unwrap_result or expect_result panicked, as they are one and the same after optimization. I don't think there's anything that can really be done here (apart from compiling without optimizations). |
it makes sense to me the LLVM has to pick one of the two. But right now it seems to be picking neither: both of the frames involved are removed completely. shouldn’t it be showing one or the other? |
Picking one of the two would be incorrect, in case it's the other one that actually gets executed. This would result in a confusing backtrace where (for example) unwrap_result panicked, but the backtrace points to expect_result instead. |
that seems better to me than having no frames for that call at all? i agree it’s not correct but i'm confused why you think it’s worse than the current situation; at least it gives you some idea of what happened. |
would it be possible to list all functions that could be called for each backtrace frame, so instead of |
I don’t think that would play very well with GDB and other tools that let you select frames by name, but maybe we could add two different DW_AT_name attributes to the DW_TAG_subprogram? i’m not sure if dwarf defines the behavior in that case, i would expect tools that don’t understand it to pick one at random. it would work fine for std’s backtrace printer though as long as we taught it to add the |
https://wiki.dwarfstd.org/ICF.md has an extension that uses .debug_dcall to disambiguate two merged functions based on the return address. maybe we could use that? |
would the return address be different, here? |
I wonder if we should treat merged functions as if one was inlined fully into the other one. (this doesn't really make sense at the source level, but) |
Would it be possible/reasonable to replace merged frames with some brief explanation of what happened? For example, by printing the stacktrace in the OP as stack backtrace:
0: rust_begin_unwind
at /rustc/14ee63a3c651bb7a243c8b07333749ab4b152e13/library/std/src/panicking.rs:676:5
1: core::panicking::panic_fmt
at /rustc/14ee63a3c651bb7a243c8b07333749ab4b152e13/library/core/src/panicking.rs:75:14
2: core::result::unwrap_failed
at /rustc/14ee63a3c651bb7a243c8b07333749ab4b152e13/library/core/src/result.rs:1704:5
3: [function merged]
4: [function merged]
5: main::main
at ./src/main.rs:5:28
6: core::ops::function::FnOnce::call_once
at /home/jyn/.local/lib/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5 Bonus points for including any additional information we can manage, such as, say, the address of the function being merged. Further bonus points for showing which functions were merged, assuming that's implementable. If nothing else, it seems slightly more intuitive than simply removing the function entirely. I was today years old when I found out backtraces can sometimes just skip frames, I expect if I'd found out by trying to debug one rather than by reading about this issue I'd have been extremely puzzled about what on earth was going on. |
@T-Dark0 We, er, eliminated the data we could use to show that. |
I tried this code:
I expected to see this happen:
Instead, this happened:
note how the line numbers have disappeared and the frames for
unwrap_result
andResult::unwrap
have disappeared.any of the following things fix the problem:
-O
expect_result
branch of the matchErr().expect()
in theexpect_result
function. Note that this function is never called; changing it should not affect runtime behavior.let x = String::from("unwrap_result")
tolet x = "unwrap_result"
. i suspect this lets llvm do constant folding or something like that?note that i consider this a bug even though
-O
is present. the whole point of debuginfo is to work with inlined functions, and extremely similar programs that are optimized will have proper backtraces.dwarfdump -i
reports that there is no debuginfo at all present forunwrap_result
; doing any of the 4 things above results in debuginfo being created. i verified with a local build of the compiler that this only affects the llvm backend, not cranelift.Meta
rustc --version --verbose
:@rustbot label A-debuginfo A-backtrace A-llvm
The text was updated successfully, but these errors were encountered: