-
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
std: Switch from libbacktrace to gimli (take 2) #74682
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
|
@bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit b2af228df5797b8cb106ca82b5a940f136cc40e4 with merge ca43ac58855c4f873de3e71b58ae3823e4290de9... |
☀️ Try build successful - checks-actions, checks-azure |
Queued ca43ac58855c4f873de3e71b58ae3823e4290de9 with parent 371917a, future comparison URL. |
Finished benchmarking try commit (ca43ac58855c4f873de3e71b58ae3823e4290de9): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
|
cc #74716 which is another revert of basically a major expansion of code in libstd. I expect that this basically means that the current implementation of the metadata loading and such in the compiler just deals really poorly with expanding dependencies (at least std). This seems to match up with what @alexcrichton has said. Hopefully, these two cases can both be resolved with similar modifications to the metadata loading in the compiler. |
@Mark-Simulacrum @nnethercote do y'all know what the next steps are here? This has basically been silent since the perf results came back? |
Yeah, I've been bogged down with the perf server being overloaded due to the increased speed of rust-lang/rust CI (due to GHA). I'm hoping to have some cycles this week to take a look at the performance here, probably by pushing some commits to this branch and/or doing some local benchmarking. I also noticed that @petrochenkov noted #74807 as likely an improvement for this PR. I can take on rebasing this and such as needed; my guess is that we'll probably take this week to examine if there's anything we can do here and then prepare a report for next week's compiler team meeting where the benefits/costs of this PR will be evaluated. I believe that we're likely to decide that the soundness and cross-compiling nature of std is more important than the performance losses here -- which are all mostly on smaller crates, and measure in large percentages but are absolutely small -- and as such approve this PR. |
I'm happy to take on the rebasing, I just want to make sure this isn't lost in the shuffle. That was the purpose of not reverting it in the first place, it's easily forgotten. Is there anything that needs to be done to place this on an agenda? |
I think LTOing backtrace crate would reduce linker regression at the expense of Rust's build time but haven't really got time to test that yet. |
Just a heads up that |
b2af228
to
f7bc182
Compare
@alexcrichton: I'm happy to do some profiling, but I can't manage to apply the patch so that it builds locally, even after @Mark-Simulacrum helped me. Is the contents of |
AFAIK this can't be downloaded as a patch because it adds a submodule, you'll need to checkout the git commit or do a cherry-pick. I'll fix the .gitmodules issue but I don't think that will help with apply this PR as a patch. |
This commit is a proof-of-concept for switching the standard library's backtrace symbolication mechanism on most platforms from libbacktrace to gimli. The standard library's support for `RUST_BACKTRACE=1` requires in-process parsing of object files and DWARF debug information to interpret it and print the filename/line number of stack frames as part of a backtrace. Historically this support in the standard library has come from a library called "libbacktrace". The libbacktrace library seems to have been extracted from gcc at some point and is written in C. We've had a lot of issues with libbacktrace over time, unfortunately, though. The library does not appear to be actively maintained since we've had patches sit for months-to-years without comments. We have discovered a good number of soundness issues with the library itself, both when parsing valid DWARF as well as invalid DWARF. This is enough of an issue that the libs team has previously decided that we cannot feed untrusted inputs to libbacktrace. This also doesn't take into account the portability of libbacktrace which has been difficult to manage and maintain over time. While possible there are lots of exceptions and it's the main C dependency of the standard library right now. For years it's been the desire to switch over to a Rust-based solution for symbolicating backtraces. It's been assumed that we'll be using the Gimli family of crates for this purpose, which are targeted at safely and efficiently parsing DWARF debug information. I've been working recently to shore up the Gimli support in the `backtrace` crate. As of a few weeks ago the `backtrace` crate, by default, uses Gimli when loaded from crates.io. This transition has gone well enough that I figured it was time to start talking seriously about this change to the standard library. This commit is a preview of what's probably the best way to integrate the `backtrace` crate into the standard library with the Gimli feature turned on. While today it's used as a crates.io dependency, this commit switches the `backtrace` crate to a submodule of this repository which will need to be updated manually. This is not done lightly, but is thought to be the best solution. The primary reason for this is that the `backtrace` crate needs to do some pretty nontrivial filesystem interactions to locate debug information. Working without `std::fs` is not an option, and while it might be possible to do some sort of trait-based solution when prototyped it was found to be too unergonomic. Using a submodule allows the `backtrace` crate to build as a submodule of the `std` crate itself, enabling it to use `std::fs` and such. Otherwise this adds new dependencies to the standard library. This step requires extra attention because this means that these crates are now going to be included with all Rust programs by default. It's important to note, however, that we're already shipping libbacktrace with all Rust programs by default and it has a bunch of C code implementing all of this internally anyway, so we're basically already switching already-shipping functionality to Rust from C. * `object` - this crate is used to parse object file headers and contents. Very low-level support is used from this crate and almost all of it is disabled. Largely we're just using struct definitions as well as convenience methods internally to read bytes and such. * `addr2line` - this is the main meat of the implementation for symbolication. This crate depends on `gimli` for DWARF parsing and then provides interfaces needed by the `backtrace` crate to turn an address into a filename / line number. This crate is actually pretty small (fits in a single file almost!) and mirrors most of what `dwarf.c` does for libbacktrace. * `miniz_oxide` - the libbacktrace crate transparently handles compressed debug information which is compressed with zlib. This crate is used to decompress compressed debug sections. * `gimli` - not actually used directly, but a dependency of `addr2line`. * `adler32`- not used directly either, but a dependency of `miniz_oxide`. The goal of this change is to improve the safety of backtrace symbolication in the standard library, especially in the face of possibly malformed DWARF debug information. Even to this day we're still seeing segfaults in libbacktrace which could possibly become security vulnerabilities. This change should almost entirely eliminate this possibility whilc also paving the way forward to adding more features like split debug information. Some references for those interested are: * Original addition of libbacktrace - rust-lang#12602 * OOM with libbacktrace - rust-lang#24231 * Backtrace failure due to use of uninitialized value - rust-lang#28447 * Possibility to feed untrusted data to libbacktrace - rust-lang#21889 * Soundness fix for libbacktrace - rust-lang#33729 * Crash in libbacktrace - rust-lang#39468 * Support for macOS, never merged - ianlancetaylor/libbacktrace#2 * Performance issues with libbacktrace - rust-lang#29293, rust-lang#37477 * Update procedure is quite complicated due to how many patches we need to carry - rust-lang#50955 * Libbacktrace doesn't work on MinGW with dynamic libs - rust-lang#71060 * Segfault in libbacktrace on macOS - rust-lang#71397 Switching to Rust will not make us immune to all of these issues. The crashes are expected to go away, but correctness and performance may still have bugs arise. The gimli and `backtrace` crates, however, are actively maintained unlike libbacktrace, so this should enable us to at least efficiently apply fixes as situations come up.
f7bc182
to
06d565c
Compare
Here is a Cachegrind diff for
Looks like it's all due to more metadata encoding. |
Is there something I need to do to ensure that this comes up on the appropriate agenda? If so, what is that? |
I don't think so -- I plan to spend some more time this week looking at that cachegrind diff and performance here in general (and have already posted at least one PR, #74887 which should have a ~1% improvement on the benchmarks that regressed here). I think once that's done we'll want to re-run try here for some "final numbers" and nominate this PR for the compiler team. My expectation is that it will then be discussed on August 6th and likely landed soon thereafter. |
Is it possible to bump this sooner on the agenda? It was intended to land this just after the beta branch to give this maximal testing on nightly to weed out unexpected regressions. Landing after August 6th delays that by 3 weeks and halves the amount of nightly testing this is going to get. I'll reiterate I'm more than happy to revert this if the decision is that it shouldn't land. Given though that this is highly likely to land I continue to not understand the very strong reluctance to put this in tree. |
Is there a way to test that ahead of time? I'm happy to do any testing for that, I just figured it wasn't really testable until this merged |
Hm okay so rust-src is broken right now anyway as a result of the src -> library move... but that should have been fixed by #74923. I guess the try build here kicked off a few hours before that merged, though. @bors try I (tried to) test the current try build by doing this:
(Obviously, we expect that to succeed). |
⌛ Trying commit 06d565c with merge 545470a83a069207bfd714fe0d7010132e3d36fc... |
☀️ Try build successful - checks-actions, checks-azure |
Needed to add |
@bors r+ rollup=never in that case. Thanks for bearing with us on this. |
📌 Commit 06d565c has been approved by |
⌛ Testing commit 06d565c with merge 66b9e8cfe2bb84b38eae2fb4eb6003ee1663791c... |
@bors retry yield |
Your PR failed (pretty log, raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem. Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
@bors treeclosed- |
☀️ Test successful - checks-actions, checks-azure |
As expected, this was a performance regression of up to 20% on smaller crates, essentially entirely due to increased amount of metadata decoding. #75008 may be the first step in eliminating these losses. |
This is the second attempt to land #73441 after being reverted in #74613. Will be gathering precise perf numbers here in this take.
Closes #71060