-
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
Differences between LLVM const-eval of floats and runtime behaviour can cause miscompilations #124364
Comments
@rustbot label +A-floating-point +A-llvm +I-unsound +A-cross |
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-high |
This different |
Shouldn't an LLVM issue be filed for this? Ideally the results of transcendentals should be represented by a "fuzzy" range, making compile time float equality impossible in this case. |
llvm/llvm-project#89885 was filed on the llvm side |
Ah, fun. So LLVM assumes that Now I wonder if the non-determinism in NaNs (as specified in rust-lang/rfcs#3514) is subject to similar issues. If LLVM assumes float operations are deterministic then indeed it must not do any const-folding that differs from the effective runtime behavior. |
@RalfJung Non-deterministic NaNs can cause miscompilations. Here is an example that works on x86-64 (playground): #[inline(never)]
fn print_vals(x: f64, i: usize, vals_i: u32) {
println!("x={x} i={i} vals[i]={vals_i}");
}
#[inline(never)]
pub fn evil(vals: &[u32; 300]) {
const INC: f64 = f64::MAX / 90.0;
let mut x: f64 = -1.0;
let mut i: usize = 0;
while x.is_sign_negative() {
print_vals(x, i, vals[i]);
// Use a big decrement to reach negative infinity quickly.
x -= INC;
// Convert infinity into a NaN (Inf - Inf = NaN)
x = x + x - x;
i += 2;
}
}
pub fn main() {
let mut vals: [u32; 300] = [0; 300];
for i in 0..300 { vals[i as usize] = i; }
evil(&vals);
} On x86-64 (and 32-bit x86), NaNs produced at runtime will always have a negative sign whereas NaNs produced by LLVM at compile time always have a positive sign. This means LLVM thinks the loop will exit when |
@beetrees thanks for constructing an example! |
llvm/llvm-project#90942 will be in #127513, so some of this may be improved soon. |
I've tested both the examples and can confirm that this issue has been fixed by #127513. |
Awesome, let's close this then. :) |
Per llvm/llvm-project#89885 (comment) that was only a partial fix, are we still exposing this in some way? |
I consider the rest to be part of <#114479>
|
I tried this code (based on an example from another issue, which is lightly adapted from @comex's example on a different issue):
I expected to see this happen: The 100% safe code never segfaults when compiled with optimisations.
Instead, this happened: When cross-compiled with optimisations to a platform with a
sin
implementation that does not produce identical results to the platform on which the code is being was compiled, the resulting binary will segfault. I discovered this by cross-compiling from x86_64-unknown-linux-gnu to x86_64-pc-windows-msvc and running the resulting binary with wine, but any pair of platforms with differingsin
implementations will do.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: