-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Bug on casting double to uint64_t #5932
Comments
Can you elaborate on this? Since 64b_maxd is the maximum uint64_t, wouldn't that be the value of Also, your proposed change is, in essence, changing What subtlety of doubles, rounding, and overflow/edge cases am I missing here? |
You got it right: the bug is exactly on the case that Let Double representation (64 bits):
A
The next number that double can represent is:
For all numbers between ( So, based on that, would be correct to check if the number is less than |
Ah, thanks for the explanation. Is this actually triggerable in PHP code, that would show a different result to PHP5? Or did you say this only shows up on non-x86 platforms, since x86 just so happens to do a conversion that makes this work out anyways? If you want to put up a PR, we'd love to take a look at it. |
Second option is the correct, this only shows up on non- Thanks for commenting, I will create the PR. |
@gut do we differ from PHP5/PHP7 in our visible behavior in PHP code? |
@jwatzman , no, you're right. That red region also happens on PHP5. However not the overflow cases:
HipHop VM 3.2.0 (rel) output:
php 5.6.11-1 output:
test based on https://github.com/facebook/hhvm/blob/master/hphp/test/quick/castDbl.php |
https://3v4l.org/YlkBj -- looks like we match older versions of PHP5, but the output changed as of 5.5 or so. |
When 'v' is equal to 'std::numeric_limits<uint64_t>::max()', it should not be casted to uint64_t, because there will be an overflow. For x86_64 machines, the cast above results in overflow, but the result is '0', i. e., the expected result. Others platforms may not behave the same way, as tested on PPC64, that returns '-1' for the same cast. Looking for make HHVM behave the same way in both platforms, this change returns '0' if the number going to be casted ('v') is equal to 'std::numeric_limits<uint64_t>::max()'. There is no behavior change for x86_64 platform. See discussion: facebook#5932. PS: tested on php5 v5.6xxx on PPC64 and that result is also supposed to be ‘0’, not ‘-1’.
Summary: When 'v' is equal to 'std::numeric_limits<uint64_t>::max()', it should not be casted to uint64_t, because there will be an overflow. For x86_64 machines, the cast above results in overflow, but the result is '0', i. e., the expected result. Others platforms may not behave the same way, as tested on PPC64, that returns '-1' for the same cast. Looking for make HHVM behave the same way in both platforms, this change returns '0' if the number going to be casted ('v') is equal to 'std::numeric_limits<uint64_t>::max()'. There is no behavior change for x86_64 platform. See discussion: #5932. PS: tested on php5 v5.6.9-1 on PPC64 and that result is also supposed to be ‘0’, not ‘-1’. Closes #6067 Reviewed By: @JoelMarcey Differential Revision: D2367616
Taking a closer look into the cast function, I could identify a behavior that would not be the correct one when checking if the double value fits in
uint64_t
.See code below (https://github.com/facebook/hhvm/blob/master/hphp/runtime/base/type-conversions.h#L69):
Let
18446744073709551616.0
be2^64
represented as double. Let’s call it 64b_maxd.If
v
has a value in the range from (64b_maxd - 1024) to (64b_maxd + 2048) the statementv > std::numeric_limits<uint64_t>::max()
returns false, resulting in a cast ofv
touint64_t
. There is no error running the code, because coincidentally the cast for that values returns "0", what is expected for a value that does not fit in a "uint64_t". This bug does not generate an error to x86_64, but may to other platforms.I coded a small test here: https://gist.github.com/lbianc/3d320a1a3f75f487e21b.
Based on that, the correct way to check if
v
value fits in auint64_t
wouldn't be verifying if it is smaller than max of "uint64_t"?The change would be:
The text was updated successfully, but these errors were encountered: