|
34 | 34 | #define NS_TO_MS (1000 * 1000)
|
35 | 35 | #define NS_TO_US (1000)
|
36 | 36 |
|
| 37 | +#if SIZEOF_TIME_T == SIZEOF_LONG_LONG |
| 38 | +# define PY_TIME_T_MAX LLONG_MAX |
| 39 | +# define PY_TIME_T_MIN LLONG_MIN |
| 40 | +#elif SIZEOF_TIME_T == SIZEOF_LONG |
| 41 | +# define PY_TIME_T_MAX LONG_MAX |
| 42 | +# define PY_TIME_T_MIN LONG_MIN |
| 43 | +#else |
| 44 | +# error "unsupported time_t size" |
| 45 | +#endif |
| 46 | + |
| 47 | +#if PY_TIME_T_MAX + PY_TIME_T_MIN != -1 |
| 48 | +# error "time_t is not a two's complement integer type" |
| 49 | +#endif |
| 50 | + |
| 51 | +#if _PyTime_MIN + _PyTime_MAX != -1 |
| 52 | +# error "_PyTime_t is not a two's complement integer type" |
| 53 | +#endif |
| 54 | + |
| 55 | + |
37 | 56 | static void
|
38 | 57 | error_time_t_overflow(void)
|
39 | 58 | {
|
@@ -157,7 +176,21 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
|
157 | 176 | }
|
158 | 177 | assert(0.0 <= floatpart && floatpart < denominator);
|
159 | 178 |
|
160 |
| - if (!_Py_InIntegralTypeRange(time_t, intpart)) { |
| 179 | + /* |
| 180 | + Conversion of an out-of-range value to time_t gives undefined behaviour |
| 181 | + (C99 §6.3.1.4p1), so we must guard against it. However, checking that |
| 182 | + `intpart` is in range is delicate: the obvious expression `intpart <= |
| 183 | + PY_TIME_T_MAX` will first convert the value `PY_TIME_T_MAX` to a double, |
| 184 | + potentially changing its value and leading to us failing to catch some |
| 185 | + UB-inducing values. The code below works correctly under the mild |
| 186 | + assumption that time_t is a two's complement integer type with no trap |
| 187 | + representation, and that `PY_TIME_T_MIN` is within the representable |
| 188 | + range of a C double. |
| 189 | +
|
| 190 | + Note: we want the `if` condition below to be true for NaNs; therefore, |
| 191 | + resist any temptation to simplify by applying De Morgan's laws. |
| 192 | + */ |
| 193 | + if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { |
161 | 194 | error_time_t_overflow();
|
162 | 195 | return -1;
|
163 | 196 | }
|
@@ -210,7 +243,8 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
|
210 | 243 | d = _PyTime_Round(d, round);
|
211 | 244 | (void)modf(d, &intpart);
|
212 | 245 |
|
213 |
| - if (!_Py_InIntegralTypeRange(time_t, intpart)) { |
| 246 | + /* See comments in _PyTime_DoubleToDenominator */ |
| 247 | + if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { |
214 | 248 | error_time_t_overflow();
|
215 | 249 | return -1;
|
216 | 250 | }
|
@@ -395,7 +429,8 @@ _PyTime_FromDouble(_PyTime_t *t, double value, _PyTime_round_t round,
|
395 | 429 | d *= (double)unit_to_ns;
|
396 | 430 | d = _PyTime_Round(d, round);
|
397 | 431 |
|
398 |
| - if (!_Py_InIntegralTypeRange(_PyTime_t, d)) { |
| 432 | + /* See comments in _PyTime_DoubleToDenominator */ |
| 433 | + if (!((double)_PyTime_MIN <= d && d < -(double)_PyTime_MIN)) { |
399 | 434 | _PyTime_overflow();
|
400 | 435 | return -1;
|
401 | 436 | }
|
@@ -722,7 +757,9 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
|
722 | 757 | info->monotonic = 0;
|
723 | 758 | info->adjustable = 1;
|
724 | 759 | if (clock_getres(CLOCK_REALTIME, &res) == 0) {
|
725 |
| - info->resolution = res.tv_sec + res.tv_nsec * 1e-9; |
| 760 | + /* the explicit (double) casts silence loss-of-precision warnings |
| 761 | + on some platforms */ |
| 762 | + info->resolution = (double)res.tv_sec + (double)res.tv_nsec * 1e-9; |
726 | 763 | }
|
727 | 764 | else {
|
728 | 765 | info->resolution = 1e-9;
|
|
0 commit comments