-
Notifications
You must be signed in to change notification settings - Fork 58
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
Guarantees (or lack thereof) of floating-point arithmetic #123
Comments
IIUC, if we were to guarantee (like the reference might already do) that arithmetic on The IEEE-754:2008 section 10.4 allows implementations to change the behavior of some of these operations for optimization purposes in an opt-in way, so a consequence of following the standard here would be that an implementation could add a flag that when enabled breaks the example above. This is not as bad as it sounds. The example above would only be safe for certains values of these options (e.g. the defaults), and users can use |
I would propose that the code sample above should always be considered unsafe, and one possible solution should be to not use Also, the proposal as written relies on an assumption about what the defaults would be, which has not yet been determined (and isn't entirely clear from the limited degree that Rust currently specifies it). That's already the subject of an existing RFC. I don't think the answer to "is the above code safe" should be "it depends", it should be "yes" or "no". (And I think it should be "no".) The above code should also be generating a lint about the use of EDIT: Also, thank you for raising this issue; I definitely think it's worth evaluating, as an orthogonal question. |
I don't think stating that the behavior of the example above is always undefined works very well without a more precise model of which exact fp operations are "deterministic" and which ones are not. For example, if that's always UB, miri should be able to execute it and error properly, but how would it do that? If all fp arithmetic is treated as non-deterministic, then:
etc. We would need to track everything that participated in a fp operation, and when something like a pointer offset, a branch, etc. happens, error in miri. It might just be much simpler and almost as useful in practice to just forbid all fp arithmetic in miri and constant evaluation. What would work is letting fp-arithmetic be implementation-defined, as long as it is deterministic (that's what IEEE-754 tries to do). Different targets can have different implementations (e.g. different libm's), but miri could implement those, and we could do fp arithmetic evaluation in miri. This means that whether the example above has UB or not is implementation defined, but you could run it under miri for a couple of implementations, and miri would let you know for which one the example does have UB. If fp-arithmetic is allowed to depend on, e.g., the optimization level, miri would need to "somehow" perform the same optimizations that LLVM does to be able to replicate the arithmetic, which probably is not feasible, so this is something that might be worth constraining. This does not mean that an implementation wouldn't be allowed to perform any optimizations, but that miri has to be able to model them. |
I strongly disagree on this one. I've worked in codebases with such warnings before, and it's not helpful, resulting in just After all, I don't want lints that are, essentially, "Go read https://dl.acm.org/doi/10.1145/103162.103163 then allow this lint". |
I do think its useful to treat x86-32 without SSE2 as a legacy architecture so, even if it's slower on x86-32, we should have fp arithmetic use the precision and range and other properties of the fp types used, and not allow promoting intermediates to |
I recently wrote a pre-RFC that proposes concrete guarantees. Under that pre-RFC, the program above is fine. The implementation for the target is just unfortunately broken. |
This comment was marked as resolved.
This comment was marked as resolved.
With rust-lang/rust#113053 having passed FCP, that is now clearly the case. So I think we can close this issue. #237 tracks writing down our NaN semantics properly. |
Once we are finished with layout and validity we might want to write down what
unsafe
Rust code is allowed to assume about floating-point arithmetic with thef32
andf64
primitive types.For example, does this code (playground) invoke undefined behavior?
Currently, this code does not invoke UB on many targets, but on
i586-unknown-linux-gnu
in debug mode this code does an access out-of-bounds.The text was updated successfully, but these errors were encountered: