-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Failure to elide bound checks for multiple slice writes by index after length check that can't overflow #55147
Comments
Your godbolt link seems to have incorrect code: pub fn unchecked(dst: &mut [u8], offset: usize) {
let mut i = offset;
if i.checked_add(4).unwrap() > dst.len() {
unsafe {
*(dst.get_unchecked_mut(i)) = 1;
i += 1;
*(dst.get_unchecked_mut(i)) = 2;
i += 1;
*(dst.get_unchecked_mut(i)) = 3;
i += 1;
*(dst.get_unchecked_mut(i)) = 4;
}
}
}
pub fn checked(dst: &mut [u8], offset: usize) {
let mut i = offset;
if i.checked_add(4).unwrap() > dst.len() {
dst[i] = 1;
i += 1;
dst[i] = 2;
i += 1;
dst[i] = 3;
i += 1;
dst[i] = 4;
}
} I'm pretty sure these |
As another side note: have you considered preslicing the input like below? pub fn checked(dst: &mut [u8], offset: usize) {
let dst = &mut dst[offset..];
if dst.len() >= 4 {
dst[0] = 1;
dst[1] = 2;
dst[2] = 3;
dst[3] = 4;
}
} I agree that optimiser should be smarter with range analysis in your example, but something like this seems more idiomatic than |
Thanks. Fixed.
It had occurred to me that there probably is a pattern that optimizes properly, but I hadn't tried that one. Thanks! It seems an additional check is needed to avoid panic when taking the subslice: pub fn checked(dst: &mut [u8], offset: usize) {
if offset <= dst.len() {
let dst = &mut dst[offset..];
if dst.len() >= 4 {
dst[0] = 1;
dst[1] = 2;
dst[2] = 3;
dst[3] = 4;
}
}
} |
Per suggestion by @RReverser in rust-lang/rust#55147 This change also makes the output buffer size requirement for UTF-16 to UTF-8 encode normal (number of input code units times three instead of the previous input code units times three plus one where the last code unit was never written into but had to be there for space checks).
Another simple case of adding a constant breaking LLVM's range analysis. It should be possible to compile this without a bound check. |
@hsivonen Your second example fails to fold due to the one-use check in https://github.com/llvm-mirror/llvm/blob/fb1e04ff3c51a617c4944b2e05e8aa1b8c543e22/lib/Transforms/InstCombine/InstCombineCompares.cpp#L2389. Recent discussion on why it can't just be dropped: https://reviews.llvm.org/D58633 There's a couple other ways in which it could be made to fold, e.g. by handling icmp (add X, C), C2 for recursive simplification in InstSimplify, or by getting CVP/LVI to do a range-based evaluation of the condition. |
Looks like these have had the same codegen since rust 1.81: https://rust.godbolt.org/z/88cdKf11W Should this be closed, or is it preferable to add a codegen test? |
We should add a codegen test. |
Ok! #134892 |
Added codegen test for elidings bounds check when indexes are manually checked Closes rust-lang#55147
Added codegen test for elidings bounds check when indexes are manually checked Closes rust-lang#55147
Added codegen test for elidings bounds check when indexes are manually checked Closes rust-lang#55147
Rollup merge of rust-lang#134892 - alex:codegen-55147, r=durin42 Added codegen test for elidings bounds check when indexes are manually checked Closes rust-lang#55147
Nightly Rust Godbolt link.
These two functions should logically compile to the same code but don't:
The output is:
That is, the safe function emits bound checks for each write via slice subscript despite there being enough information to decide that the bound checks cannot fail.
In
encoding_rs
the use ofunsafe
as seen in the first function is necessary for the UTF-16 to UTF-8 encoder to be competitive with C++.The text was updated successfully, but these errors were encountered: