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

Inexact and/or Wrong {From,To}Primitive #10481

Closed
lifthrasiir opened this issue Nov 14, 2013 · 13 comments
Closed

Inexact and/or Wrong {From,To}Primitive #10481

lifthrasiir opened this issue Nov 14, 2013 · 13 comments
Labels
P-medium Medium priority

Comments

@lifthrasiir
Copy link
Contributor

Motivating examples:

(100_0000_0000_0000_2345u64).to_f64(); // => Some(1000000000000002244f64)
(42.5f64).to_u8(); // => Some(42u8)
(42.5e80f64).to_u8(); // => Some(0u8)
(42.5e80f64).to_i32(); // => Some(-2147483648i32)

Note that the last two results can change depending on your optimization level. (Is it another issue?) It seems that it's due to the constant propagation across inlined function calls.

Currently we check for such cases in int to int and float to float conversion, but we don't check (and solely rely on casting) in int to float and float to int conversion. This can cause the inexact computation in two ways: unwanted truncation, and failed bound check. Four possible decisions have their pros and cons respectively, but should be decided and documented.

@huonw
Copy link
Member

huonw commented Nov 14, 2013

(100_0000_0000_0000_2345u64).to_f64(); // => Some(1000000000000002244f64)

This appears to just be floating point precision, although (python3):

>>> int(float(1000000000000002345))
1000000000000002304

so we're not doing the best job possible.

(Personally, I'd think that returning None as soon as any precision is lost for int -> float would make these traits much less useful... it's just a hazard of working with floating point.)

The others are concerning though.

@huonw
Copy link
Member

huonw commented Nov 14, 2013

Also,

Note that the last two results can change depending on your optimization level. (Is it another issue?) It seems that it's due to the constant propagation across inlined function calls.

Is likely because the result is undefined if the value doesn't fit in result type (and clearly 42.5e80 doesn't fit in a u8 or i32).

The ‘fptoui‘ instruction converts its floating point operand into the nearest (rounding towards zero) unsigned integer value. If the value cannot fit in ty2, the results are undefined.

docs: float → unsigned, float → signed

@lifthrasiir
Copy link
Contributor Author

@huonw I agree that the strict exactness would make the methods less useful, but this fact itself should be documented somehow. (Or, if we are extra careful about this issue, we can add to_i32_exact() etc. Aren't we already have traits for saturating arithmetics?) For the undefined behavior for fptoui, it looks like a copy of C/C++'s semantics (naturally); in Rust we already have bound-checking conversion methods (e.g. 65536u.to_i16() == None) so it is more important to be consistent.

@huonw
Copy link
Member

huonw commented Nov 14, 2013

in Rust we already have bound-checking conversion methods (e.g. 65536u.to_i16() == None) so it is more important to be consistent.

Yep, I definitely agree that they should be bounds-checked, I'd guess that it was just @erickt overlooking the float conversions.

@nikomatsakis
Copy link
Contributor

As @thestinger pointed out, undefined results -- particularly of
integral type -- are much worse than previously believed and can lead
to bounds check violations and so forth, so I guess we do need to fix
this.

@nikomatsakis
Copy link
Contributor

Nominating.

@pcwalton
Copy link
Contributor

We need -fwrapv.

@pnkfelix
Copy link
Member

pcwalton recommends we adopt an approach of implementing the equivalent of:

-fwrapv
    This option instructs the compiler to assume that signed arithmetic overflow of addition, subtraction and 
multiplication wraps around using twos-complement representation. This flag enables some optimizations and 
disables others. This option is enabled by default for the Java front end, as required by the Java language 
specification.

@pnkfelix
Copy link
Member

Accepted for P-high; it is a potential (though at least known) soundness hole, and thus a security bug. But we are permitted to still leave such things for post 1.0 (they are just still high priority in that context).

@alexcrichton
Copy link
Member

It appears that to support -fwrapv we would need to simply build arithmetic instructions differently. The clang implementation simply calls the corresponding LLVM builder function, and I imagine that we would do something similar.

I'm unsure of whether we'd want to do this in all arithmetic, though, or only in some cases.

@treeman
Copy link
Contributor

treeman commented Sep 1, 2014

Visiting for triage, still relevant.

@bombless
Copy link
Contributor

Luckily ToPrimitive was gone so we don't have this problem in std any more.

@arielb1
Copy link
Contributor

arielb1 commented Jun 29, 2015

The last of these is just a duplicate of #10184, the others are expected behaviour.

@arielb1 arielb1 closed this as completed Jun 29, 2015
flip1995 pushed a commit to flip1995/rust that referenced this issue Mar 24, 2023
Add `allow_attribute` lint

Fixes rust-lang#10468

changelog: new lint: [`allow_attributes`]
[rust-lang#10481](rust-lang/rust-clippy#10481)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P-medium Medium priority
Projects
None yet
Development

No branches or pull requests

9 participants