-
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
Avoid panic_bounds_check in fmt::write. #78122
Avoid panic_bounds_check in fmt::write. #78122
Conversation
Writing any fmt::Arguments would trigger the inclusion of usize formatting and padding code in the resulting binary, because indexing used in fmt::write would generate code using panic_bounds_check, which prints the index and length. These bounds checks are not necessary, as fmt::Arguments never contains any out-of-bounds indexes. This change replaces them with unsafe get_unchecked, to reduce the amount of generated code, which is especially important for embedded targets.
r? @dtolnay (rust_highfive has picked a reviewer for you, use r? to override) |
Related optimization: rust/library/core/src/panicking.rs Lines 44 to 50 in a85e949
That optimzation would not be very effective if even writing the most trivial Not sure if this can (or should) be tested for. Checking if some code results in a binary smaller than some threshold would not be a good test. Coming up with a somewhat complete list of symbols that 'should not be there' is also not easy. |
@rustbot modify labels: +A-fmt +I-heavy +libs-impl |
Error: Label libs-impl can only be set by Rust team members Please let |
@rustbot modify labels: +A-fmt +I-heavy +T-libs |
I think it would be good to see if we can add a simple codegen test to assert that there's no panic/bounds check here, since it seems easy for it to sneak back in. I would also like debug asserts here - the compiler should be correct, but I'm not sure we're testing that anywhere else (other than kinda via these bounds checks and such). |
@Mark-Simulacrum sounds good. Will add that when I have time. @rustbot modify labels: +S-waiting-on-author -S-waiting-on-review |
Added the debug_asserts and a test. The test is a @rustbot modify labels: -S-waiting-on-author +S-waiting-on-review |
src/test/run-make/fmt-write-bloat/main doesn't need to be checked in, 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.
This seems good to me -- r=me with the binary file removed.
1158ec5
to
356d5b5
Compare
Oh oops. Accidentally committed some things I shouldn't have. Thanks. Updated. |
@bors r=Mark-Simulacrum I confirmed that the new test fails without the changes in the PR.
|
📌 Commit 356d5b5 has been approved by |
@m-ou-se I believe this is waiting on you to implement the fix suggested in #78122 (comment), which would permanently designate the llvm-8 (now 9, IIRC) builder to be debug-assert free and test this test only when debug assertions are off. Do you need something from me to coordinate that? |
Oh, thanks for the reminder! I'll probably have time to do this in the next few days. |
Looks like there's a lot more runners on which debug assertions are disabled than I originally thought. (i686-gnu, x86_64-gnu-llvm-8, x86_64-gnu-distcheck, i686-gnu-nopt, ..) I've changed the test to only check for the
I only found a I saw one other test that greps through |
This looks good to me. Could you squash the test adding commits? r=me with that done. (FWIW I'm happy on smaller PRs to just always squash commits, and I think generally our policy of "add new commits" does more harm than good on average). |
5df04f3
to
85b217d
Compare
For most PRs I personally find it hard to review them with force-pushes between the reviews, which is why I usually use new commits after a review. Squashed the test commits into one. @bors r=Mark-Simulacrum |
📌 Commit 85b217d1d66d2cb61cf4b6d9cf5c0fc7a28c7831 has been approved by |
⌛ Testing commit 85b217d1d66d2cb61cf4b6d9cf5c0fc7a28c7831 with merge 614ccbb44cca6b1bee828395ef4cebe629b27c92... |
💔 Test failed - checks-actions |
It checks that fmt::write by itself doesn't pull in any panicking or or display code.
85b217d
to
1da5780
Compare
This failed on Windows because the no_std test (using |
@bors r+ |
📌 Commit 1da5780 has been approved by |
@@ -1096,25 +1098,37 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { | |||
Ok(()) | |||
} | |||
|
|||
fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result { | |||
unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result { |
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.
Nit: I'd add a // SAFETY: arg and args must come from the same Arguments
comment to the newly unsafe functions as well to indicate the necessary preconditions when calling them.
☀️ Test successful - checks-actions |
Writing any fmt::Arguments would trigger the inclusion of usize formatting and padding code in the resulting binary, because indexing used in fmt::write would generate code using panic_bounds_check, which prints the index and length.
These bounds checks are not necessary, as fmt::Arguments never contains any out-of-bounds indexes.
This change replaces them with unsafe get_unchecked, to reduce the amount of generated code, which is especially important for embedded targets.
Demonstration of the size of and the symbols in a 'hello world' no_std binary:
Source code
Before:
After: