|
1 | 1 | #include "Python.h"
|
2 |
| -#include "pycore_pymath.h" // _Py_InIntegralTypeRange() |
3 | 2 | #ifdef MS_WINDOWS
|
4 | 3 | # include <winsock2.h> // struct timeval
|
5 | 4 | #endif
|
|
41 | 40 | # error "unsupported time_t size"
|
42 | 41 | #endif
|
43 | 42 |
|
| 43 | +#if PY_TIME_T_MAX + PY_TIME_T_MIN != -1 |
| 44 | +# error "time_t is not a two's complement integer type" |
| 45 | +#endif |
| 46 | + |
| 47 | +#if _PyTime_MIN + _PyTime_MAX != -1 |
| 48 | +# error "_PyTime_t is not a two's complement integer type" |
| 49 | +#endif |
| 50 | + |
44 | 51 |
|
45 | 52 | static void
|
46 | 53 | pytime_time_t_overflow(void)
|
@@ -294,7 +301,21 @@ pytime_double_to_denominator(double d, time_t *sec, long *numerator,
|
294 | 301 | }
|
295 | 302 | assert(0.0 <= floatpart && floatpart < denominator);
|
296 | 303 |
|
297 |
| - if (!_Py_InIntegralTypeRange(time_t, intpart)) { |
| 304 | + /* |
| 305 | + Conversion of an out-of-range value to time_t gives undefined behaviour |
| 306 | + (C99 §6.3.1.4p1), so we must guard against it. However, checking that |
| 307 | + `intpart` is in range is delicate: the obvious expression `intpart <= |
| 308 | + PY_TIME_T_MAX` will first convert the value `PY_TIME_T_MAX` to a double, |
| 309 | + potentially changing its value and leading to us failing to catch some |
| 310 | + UB-inducing values. The code below works correctly under the mild |
| 311 | + assumption that time_t is a two's complement integer type with no trap |
| 312 | + representation, and that `PY_TIME_T_MIN` is within the representable |
| 313 | + range of a C double. |
| 314 | +
|
| 315 | + Note: we want the `if` condition below to be true for NaNs; therefore, |
| 316 | + resist any temptation to simplify by applying De Morgan's laws. |
| 317 | + */ |
| 318 | + if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { |
298 | 319 | pytime_time_t_overflow();
|
299 | 320 | return -1;
|
300 | 321 | }
|
@@ -349,7 +370,8 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
|
349 | 370 | d = pytime_round(d, round);
|
350 | 371 | (void)modf(d, &intpart);
|
351 | 372 |
|
352 |
| - if (!_Py_InIntegralTypeRange(time_t, intpart)) { |
| 373 | + /* See comments in pytime_double_to_denominator */ |
| 374 | + if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { |
353 | 375 | pytime_time_t_overflow();
|
354 | 376 | return -1;
|
355 | 377 | }
|
@@ -507,8 +529,9 @@ pytime_from_double(_PyTime_t *tp, double value, _PyTime_round_t round,
|
507 | 529 | d *= (double)unit_to_ns;
|
508 | 530 | d = pytime_round(d, round);
|
509 | 531 |
|
510 |
| - if (!_Py_InIntegralTypeRange(_PyTime_t, d)) { |
511 |
| - pytime_overflow(); |
| 532 | + /* See comments in pytime_double_to_denominator */ |
| 533 | + if (!((double)_PyTime_MIN <= d && d < -(double)_PyTime_MIN)) { |
| 534 | + pytime_time_t_overflow(); |
512 | 535 | return -1;
|
513 | 536 | }
|
514 | 537 | _PyTime_t ns = (_PyTime_t)d;
|
@@ -902,7 +925,7 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
|
902 | 925 | info->monotonic = 0;
|
903 | 926 | info->adjustable = 1;
|
904 | 927 | if (clock_getres(CLOCK_REALTIME, &res) == 0) {
|
905 |
| - info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
| 928 | + info->resolution = (double)res.tv_sec + (double)res.tv_nsec * 1e-9; |
906 | 929 | }
|
907 | 930 | else {
|
908 | 931 | info->resolution = 1e-9;
|
|
0 commit comments