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

Confirm that transmuting floats is sound #1121

Closed
joshlf opened this issue Apr 18, 2024 · 1 comment
Closed

Confirm that transmuting floats is sound #1121

joshlf opened this issue Apr 18, 2024 · 1 comment

Comments

@joshlf
Copy link
Member

joshlf commented Apr 18, 2024

Overview

Two comments in the standard library call into question the soundness of f32-u32 transmutations. This suggests that we should be skeptical of any transmutations involving f32 or f64 as either the source or destination type.

Details

This comment in the standard library suggests that we may need to worry about whether transmuting f32 to u32 is sound:

        // SAFETY: `u32` is a plain old datatype so we can always transmute to it.
        // ...sorta.
        //
        // It turns out that at runtime, it is possible for a floating point number
        // to be subject to a floating point mode that alters nonzero subnormal numbers
        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
        // This is not a problem per se, but at least one tier2 platform for Rust
        // actually exhibits this behavior by default.
        //
        // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
        // i.e. not soft-float, the way Rust does parameter passing can actually alter
        // a number that is "not infinity" to have the same exponent as infinity,
        // in a slightly unpredictable manner.
        //
        // And, of course evaluating to a NaN value is fairly nondeterministic.
        // More precisely: when NaN should be returned is knowable, but which NaN?
        // So far that's defined by a combination of LLVM and the CPU, not Rust.
        // This function, however, allows observing the bitstring of a NaN,
        // thus introspection on CTFE.
        //
        // In order to preserve, at least for the moment, const-to-runtime equivalence,
        // we reject any of these possible situations from happening.

Later in the same file, we have this comment, which suggests that we may need to worry about the inverse - whether transmuting from u32 to f32 is sound:

        // It turns out the safety issues with sNaN were overblown! Hooray!
        // SAFETY: `u32` is a plain old datatype so we can always transmute from it
        // ...sorta.
        //
        // It turns out that at runtime, it is possible for a floating point number
        // to be subject to floating point modes that alter nonzero subnormal numbers
        // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
        // This is not a problem usually, but at least one tier2 platform for Rust
        // actually exhibits this behavior by default: thumbv7neon
        // aka "the Neon FPU in AArch32 state"
        //
        // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
        // i.e. not soft-float, the way Rust does parameter passing can actually alter
        // a number that is "not infinity" to have the same exponent as infinity,
        // in a slightly unpredictable manner.
        //
        // And, of course evaluating to a NaN value is fairly nondeterministic.
        // More precisely: when NaN should be returned is knowable, but which NaN?
        // So far that's defined by a combination of LLVM and the CPU, not Rust.
        // This function, however, allows observing the bitstring of a NaN,
        // thus introspection on CTFE.
        //
        // In order to preserve, at least for the moment, const-to-runtime equivalence,
        // reject any of these possible situations from happening.

The first line of this comment:

        // It turns out the safety issues with sNaN were overblown! Hooray!

...can be traced back to this commit, and further to this commit, where it appears to actually have been moved from this line. At this point, I stopped bothering to follow it - it seems like the current comments probably capture all that we need to know anyway.

@joshlf joshlf mentioned this issue Apr 18, 2024
87 tasks
@joshlf
Copy link
Member Author

joshlf commented Sep 10, 2024

On further evaluation, I'm confident based on rust-lang/rust@b825477 (which removes the scary comments) that we're in one of two situations:

  • This is totally fine
  • This isn't totally fine for reasons that are not our fault

Similar to our target architecture support policy, since the Reference guarantees floating point bit validity, if transmuting floats ends up being unsound on a given platform, that's Rust failing to uphold its own promise, which is not our problem.

@joshlf joshlf closed this as completed Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant