-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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 a new compare_bytes
intrinsic instead of calling memcmp
directly
#114382
Conversation
r? @cjgillot (rustbot has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
51c1830
to
e5b23a6
Compare
This comment has been minimized.
This comment has been minimized.
e5b23a6
to
029d660
Compare
This comment has been minimized.
This comment has been minimized.
029d660
to
4bccdab
Compare
This comment has been minimized.
This comment has been minimized.
4bccdab
to
f732b5a
Compare
The Miri subtree was changed cc @rust-lang/miri |
This comment has been minimized.
This comment has been minimized.
f732b5a
to
d29af67
Compare
library/core/src/intrinsics.rs
Outdated
/// | ||
/// # Safety | ||
/// | ||
/// * If `bytes` is zero, `left` and `right` must be non-null. |
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.
/// * If `bytes` is zero, `left` and `right` must be non-null. | |
/// * Even if `bytes` is zero, `left` and `right` must be non-null. |
otherwise this reads surprisingly if you don't already know about this
let left = self.read_pointer(left)?; | ||
let right = self.read_pointer(right)?; | ||
let n = Size::from_bytes(self.read_target_usize(byte_count)?); | ||
let result = if n == Size::ZERO { |
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 shouldn't be needed. Please copy the current memcmp from Miri.
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.
Ah, I didn't know that it would already do the right null checks without also requiring "real" alloc ids. I'll remove the extra checks.
(And yes, that's where I got read_bytes_ptr_strip_provenance
🙂)
@rustbot author
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.
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.
Looks good. :)
The checks Miri's functions do by default should exactly match what the docs call "valid for reads of size N", that's why you don't need any extra checks. This also ensures we apply the exact same checks everywhere (direct memory accesses, memcpy, memset, memcmp, ...).
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.
Nice! I like the synergy between that and your notes about how to document it.
(More updates coming for the other comments.)
library/core/src/intrinsics.rs
Outdated
/// # Safety | ||
/// | ||
/// * If `bytes` is zero, `left` and `right` must be non-null. | ||
/// | ||
/// * If `bytes` is non-zero, | ||
/// | ||
/// * `left` must be [valid] for reads of `bytes` bytes, | ||
/// all of which must be initialized. | ||
/// | ||
/// * `right` must be [valid] for reads of `bytes` bytes, | ||
/// all of which must be initialized. |
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 this should follow the usual documentation of all our intrinsics: left and right must be valid for reads of size bytes
. That's all we need to say.
We already say that as far as Rust is concerned, 4 as *const u8
is valid for reads of size 0. We shouldn't special-case "if bytes is zero" here in the docs nor in the Miri implementation.
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.
In particular, if we ever declare that even the null pointer is valid for zero-sized reads and writes (which we may, rust-lang/opsem-team#12), then even passing null to these intrinsics should be allowed.
--> $DIR/const-compare-bytes-ub.rs:34:9 | ||
| | ||
LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc25[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory |
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 you add a test that involves provenance? As in, pass in a buffer that contains pointers.
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.
Something like compare_bytes([&0].as_ptr(), [&0].as_ptr(), size_of_val(&0))
should probably do it
@@ -18,7 +18,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro | |||
use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*; | |||
#[macro_use /* 0#1 */] | |||
extern crate core /* 0#1 */; | |||
extern crate compiler_builtins /* 443 */ as _ /* 0#1 */; | |||
extern crate compiler_builtins /* 444 */ as _ /* 0#1 */; |
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 have no idea how this is impacted, but 🤷
d29af67
to
1f4b525
Compare
Comments here too? rust/library/core/src/slice/cmp.rs Line 77 in 11467b1
rust/library/core/src/slice/cmp.rs Line 186 in 11467b1
Line 23 in 11467b1
rust/compiler/rustc_codegen_llvm/src/context.rs Lines 893 to 898 in 11467b1
|
@bors r- |
1ac2710
to
febffe2
Compare
This comment has been minimized.
This comment has been minimized.
febffe2
to
75277a6
Compare
Updated those comments in https://github.com/rust-lang/rust/compare/1ac2710780489b50a5feb5e838f8c81a66720dbc..febffe212880dfef083bb860de45abc5aa075a3a, and rebased to pick up another proc-macro test change. @bors r=cjgillot |
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#98935 (Implement `Option::take_if`) - rust-lang#114093 (Add regression test for `echo 'mod unknown;' | rustc -`) - rust-lang#114229 (Nest tests/codegen/sanitizer*.rs tests in sanitizer dir) - rust-lang#114230 (Nest other codegen test topics) - rust-lang#114362 (string.rs: remove "Basic usage" text) - rust-lang#114365 (str.rs: remove "Basic usage" text) - rust-lang#114382 (Add a new `compare_bytes` intrinsic instead of calling `memcmp` directly) - rust-lang#114549 (Style fix and refactor on resolve diagnostics) r? `@ghost` `@rustbot` modify labels: rollup
…r=cjgillot Add a new `compare_bytes` intrinsic instead of calling `memcmp` directly As discussed in rust-lang#113435, this lets the backends be the place that can have the "don't call the function if n == 0" logic, if it's needed for the target. (I didn't actually *add* those checks, though, since as I understood it we didn't actually need them on known targets?) Doing this also let me make it `const` (unstable), which I don't think `extern "C" fn memcmp` can be. cc `@RalfJung` `@Amanieu`
document our assumptions about symbols provided by the libc LLVM makes assumptions about `memcmp`, `memmove`, and `memset` that go beyond what the C standard guarantees -- see https://reviews.llvm.org/D86993. Since we use LLVM, we are inheriting these assumptions. With rust-lang#114382 we are also making a similar assumption about `memcmp`, so I added that to the list. Fixes rust-lang/unsafe-code-guidelines#426.
document our assumptions about symbols provided by the libc LLVM makes assumptions about `memcmp`, `memmove`, and `memset` that go beyond what the C standard guarantees -- see https://reviews.llvm.org/D86993. Since we use LLVM, we are inheriting these assumptions. With rust-lang/rust#114382 we are also making a similar assumption about `memcmp`, so I added that to the list. Fixes rust-lang/unsafe-code-guidelines#426.
…r=cjgillot Add a new `compare_bytes` intrinsic instead of calling `memcmp` directly As discussed in rust-lang#113435, this lets the backends be the place that can have the "don't call the function if n == 0" logic, if it's needed for the target. (I didn't actually *add* those checks, though, since as I understood it we didn't actually need them on known targets?) Doing this also let me make it `const` (unstable), which I don't think `extern "C" fn memcmp` can be. cc `@RalfJung` `@Amanieu`
As discussed in #113435, this lets the backends be the place that can have the "don't call the function if n == 0" logic, if it's needed for the target. (I didn't actually add those checks, though, since as I understood it we didn't actually need them on known targets?)
Doing this also let me make it
const
(unstable), which I don't thinkextern "C" fn memcmp
can be.cc @RalfJung @Amanieu