-
-
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -221,10 +221,27 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); | |
#define _Py_IntegralTypeMax(type) ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0) | ||
/* Return the minimum value of integral type *type*. */ | ||
#define _Py_IntegralTypeMin(type) ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0) | ||
/* Check whether *v* is in the range of integral type *type*. This is most | ||
* useful if *v* is floating-point, since demoting a floating-point *v* to an | ||
* integral type that cannot represent *v*'s integral part is undefined | ||
* behavior. */ | ||
#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type)) | ||
|
||
/* 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 | ||
* double, and type_min() and type_max() integers are rounded towards zero when | ||
* casted to a double. | ||
* | ||
* (double)int cast rounds to nearest with ties going to nearest even integer | ||
* (ROUND_HALF_EVEN). Use nextafter() to round towards zeros (ROUND_DOWN). | ||
* | ||
* For example, _Py_IntegralTypeMax(int64_t)=2**63-1 casted to double gives | ||
* 2**63 which is greater than 2**63-1. The problem is that "v <= 2**63" fails | ||
* to detect that v will overflow when casted to int64_t. | ||
* nextafter((double)(2**63-1), 0.0) gives the floating-point number 2**63-1024 | ||
* which is less than or equal to the integer 2**63-1 and so can be used to | ||
* test that v would overflow. | ||
* | ||
* 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 commentThe 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:
but what we actually want is:
or if we want to use
For a 64-bit signed integer type, this condition becomes:
but the actual limits we need are
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggested alternative approach: given a double Similarly for |
||
&& v <= nextafter((double)_Py_IntegralTypeMax(type), 0.0)) | ||
|
||
#endif /* Py_PYMATH_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Fix :func:`time.sleep` to properly detect integer overflow when converting a | ||
floating-point number of seconds to an integer. |
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 be2147483647
. Ifv = 2147483647.5
(which is exactly representable in IEEE 754 binary64 floating-point), then it satisfies the first condition - it doesn't overflow when cast toint
- but not the second.