Skip to content
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

Add debug assertions to validate NUL terminator in c strings #93979

Merged
merged 1 commit into from
Feb 19, 2022

Conversation

SUPERCILEX
Copy link
Contributor

The unchecked variants from the stdlib usually perform the check anyway if debug assertions are on (for example, unwrap_unchecked). This PR does the same thing for CStr and CString, validating the correctness for the NUL byte in debug mode.

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @dtolnay (or someone else) soon.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 13, 2022
@SUPERCILEX SUPERCILEX changed the title Add debug asserts to validate NUL terminator in c strings Add debug assertions to validate NUL terminator in c strings Feb 13, 2022
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Thanks!

@@ -449,12 +449,18 @@ impl CString {
/// let c_string = CString::from_vec_unchecked(raw);
/// }
/// ```
#[inline(always)]
Copy link
Member

Choose a reason for hiding this comment

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

What's the justification for this attribute? inline(always) is very rarely appropriate in libstd.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thinking was that the public method now simply forwards to the internal method, so it should be removed to match the performance of not having that extra layer of indirection.

Copy link
Member

Choose a reason for hiding this comment

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

the public method now simply forwards to the internal method

This is not accurate if _from_vec_unchecked already got inlined into from_vec_unchecked. In that situation inline(always) would be forcing a potentially much larger chunk of code than intended to be duplicated into every call site.

We tend to be skeptical of inline(always) without compelling benchmarks that demonstrate it's the only way to achieve certain commonly-necessary optimizations downstream.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So inlining is bottom up rather than top down? I was thinking that from_vec_unchecked would get inlined first (so the call site now uses _from_vec_unchecked) and only then would the inliner consider _from_vec_unchecked. You're making it sound like _from_vec_unchecked could be inlined into from_vec_unchecked and then all of that gets inlined into the call site.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah it's bottom up: https://llvm.org/docs/Passes.html#inline-function-integration-inlining

Bottom-up inlining of functions into callees.

Copy link
Contributor Author

@SUPERCILEX SUPERCILEX Feb 16, 2022

Choose a reason for hiding this comment

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

Dang, bummer. Fixed, except for _from_bytes_with_nul_unchecked which I changed to always since it's just a cast.

https://github.com/rust-lang/rust/compare/f243b98120838674c04eed26401164d5255c46f8..3dbb679e05b5ee575e200c5881f450db12174201

library/std/src/ffi/c_str/tests.rs Outdated Show resolved Hide resolved
@SUPERCILEX SUPERCILEX force-pushed the debug_check branch 2 times, most recently from f243b98 to 3dbb679 Compare February 16, 2022 01:52
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Could you please remove those inlines too, unless you have some evidence that they aren't already being inlined automatically and that inlining there is necessary for achieving good enough performance? Inlining more than necessary just slows down compile time and adds maintenance burden and noise to the standard library implementation. In libstd inline(always) is very rarely appropriate.

@dtolnay dtolnay added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 17, 2022
@SUPERCILEX
Copy link
Contributor Author

SUPERCILEX commented Feb 17, 2022

@dtolnay remove them completely? from_bytes_with_nul_unchecked was already marked inline before this PR which is why I'm pushing back. Comes from here: #42716. I don't want to undo that work without a valid reason.

I just downgraded the always to a normal inline so it matches what was already there, but I can remove it completely if that's preferred.

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

This looks good. Thanks!

@dtolnay
Copy link
Member

dtolnay commented Feb 17, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Feb 17, 2022

📌 Commit 897c8d0 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 17, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 19, 2022
…askrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#92902 (Improve the documentation of drain members)
 - rust-lang#93658 (Stabilize `#[cfg(panic = "...")]`)
 - rust-lang#93954 (rustdoc-json: buffer output)
 - rust-lang#93979 (Add debug assertions to validate NUL terminator in c strings)
 - rust-lang#93990 (pre rust-lang#89862 cleanup)
 - rust-lang#94006 (Use a `Field` in `ConstraintCategory::ClosureUpvar`)
 - rust-lang#94086 (Fix ScalarInt to char conversion)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 26dd6ac into rust-lang:master Feb 19, 2022
@rustbot rustbot added this to the 1.60.0 milestone Feb 19, 2022
@SUPERCILEX SUPERCILEX deleted the debug_check branch October 16, 2022 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants