-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
bpo-39277, pytime: Fix overflow check on double to int cast #17933
Conversation
Fix time.sleep() to properly detect integer overflow when converting a floating-point number of seconds to an integer.
cc @mdickinson |
/* Check if the floating-point number v (double) would overflow when casted to | ||
* the integral type 'type'. | ||
* | ||
* Test (double)type_min(type) <= v <= (double)type_max(type) where v is a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two conditions "v would overflow when cast to 'type'" and "type_MIN <= v <= type_MAX" are not equivalent. Which one do you want to test here?
For example, assuming a 32-bit int
type: type_MAX
would be 2147483647
. If v = 2147483647.5
(which is exactly representable in IEEE 754 binary64 floating-point), then it satisfies the first condition - it doesn't overflow when cast to int
- but not the second.
* | ||
* In short, nextafter((double)x, 0.0) rounds the integer x towards zero. */ | ||
#define _Py_DoubleInIntegralTypeRange(type, v) \ | ||
(nextafter((double)_Py_IntegralTypeMin(type), 0.0) <= v \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but this isn't right.
For a 32-bit signed integer type, this condition becomes:
-2147483647.9999998 <= v <= 2147483646.9999998
but what we actually want is:
-2147483649.0 < v < 2147483648.0
or if we want to use <=
and express the limits in terms of doubles:
-2147483648.9999995 <= v <= 2147483647.9999998
For a 64-bit signed integer type, this condition becomes:
-9223372036854774784.0 <= v <= 9223372036854774784.0
but the actual limits we need are
-9223372036854775808.0 <= v <= 9223372036854774784.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested alternative approach: given a double v
that we want to safely convert to an int
(say), first use modf
to extract the fractional part fv
and the integer part iv
of v
(both fv
and iv
are still doubles at this point). We can just ignore the fractional part fv
: it doesn't affect whether we can safely cast to int
or not. Now for iv
, check whether it satisfies (double)INT_MIN <= iv
and iv < -(double)INT_MIN
. Note that INT_MIN
is (always in practice, even though not guaranteed by the standard) the negation of a power of two, so the conversion to double
doesn't change the value and we're effectively checking whether iv
lies in the half-open interval [INT_MIN, -INT_MIN)
. Since iv
is an integer, that's equivalent to checking whether iv
lies in the closed interval [INT_MIN, -INT_MIN-1]
. But making all our usual assumptions about integer representation (two's complement, no trap representation, no padding bits, etc.), -INT_MIN-1
is the same as INT_MAX
, so we're effectively checking that the integer part of v
is representable as an int
, which is exactly what we want to be checking.
Similarly for long
, long long
, etc.
A safe way to do what you want is: (1) Take the integral part of the double Computing The reason that step (2) is safe is that, making the fairly safe assumption of 2s complement (no trap representation, etc., etc.) for signed integers, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't the right way to check for convertibility; see the other comments I made on the PR.
When you're done making the requested changes, leave the comment: And if you don't make the requested changes, you will be put in the comfy chair! |
@vstinner any update on this? |
I failed finding time to finish the PR. I prefer to abandon it. |
Fix time.sleep() to properly detect integer overflow when converting
a floating-point number of seconds to an integer.
https://bugs.python.org/issue39277