Closed beetrees closed 3 weeks ago
@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 sin
implementations problem was previously reported as https://github.com/rust-lang/rust/issues/109118
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.
https://github.com/llvm/llvm-project/issues/89885 was filed on the llvm side
Ah, fun. So LLVM assumes that sin
is deterministic. Yeah that's clearly incoherent.
Now I wonder if the non-determinism in NaNs (as specified in https://github.com/rust-lang/rfcs/pull/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 x
becomes a NaN, but at runtime the loop will never exit.
@beetrees thanks for constructing an example!
https://github.com/llvm/llvm-project/pull/90942 will be in https://github.com/rust-lang/rust/pull/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 https://github.com/llvm/llvm-project/issues/89885#issuecomment-2119711089 that was only a partial fix, are we still exposing this in some way?
I consider the rest to be part of https://github.com/rust-lang/rust/issues/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
: