bpo-39277, pytime: Fix overflow check on double to int cast
Fix time.sleep() to properly detect integer overflow when converting a floating-point number of seconds to an integer.
This commit is contained in:
parent
a796d8ef9d
commit
9630d9f87a
|
@ -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 \
|
||||
&& v <= nextafter((double)_Py_IntegralTypeMax(type), 0.0))
|
||||
|
||||
#endif /* Py_PYMATH_H */
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix :func:`time.sleep` to properly detect integer overflow when converting a
|
||||
floating-point number of seconds to an integer.
|
|
@ -151,7 +151,7 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
|||
}
|
||||
assert(0.0 <= floatpart && floatpart < denominator);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(time_t, intpart)) {
|
||||
if (!_Py_DoubleInIntegralTypeRange(time_t, intpart)) {
|
||||
error_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
|
|||
d = _PyTime_Round(d, round);
|
||||
(void)modf(d, &intpart);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(time_t, intpart)) {
|
||||
if (!_Py_DoubleInIntegralTypeRange(time_t, intpart)) {
|
||||
error_time_t_overflow();
|
||||
return -1;
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ _PyTime_FromDouble(_PyTime_t *t, double value, _PyTime_round_t round,
|
|||
d *= (double)unit_to_ns;
|
||||
d = _PyTime_Round(d, round);
|
||||
|
||||
if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
|
||||
if (!_Py_DoubleInIntegralTypeRange(_PyTime_t, d)) {
|
||||
_PyTime_overflow();
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue