]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
pytime: add _PyTime_check_mul_overflow() macro to avoid undefined behaviour
authorVictor Stinner <victor.stinner@gmail.com>
Thu, 10 Sep 2015 13:55:07 +0000 (15:55 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Thu, 10 Sep 2015 13:55:07 +0000 (15:55 +0200)
Overflow test in test_FromSecondsObject() fails on FreeBSD 10.0 buildbot which
uses clang. clang implements more aggressive optimization which gives
different result than GCC on undefined behaviours.

Check if a multiplication will overflow, instead of checking if a
multiplicatin had overflowed, to avoid undefined behaviour.

Add also debug information if the test on overflow fails.

Lib/test/test_time.py
Python/pytime.c

index 30b01d5f4baf35f7f031dad85d24786b33dbc596..f883c45d04d72da5bc2d80801c12ae029d413871 100644 (file)
@@ -781,7 +781,8 @@ class CPyTimeTestCase:
         overflow_values = convert_values(ns_timestamps)
         for time_rnd, _ in ROUNDING_MODES :
             for value in overflow_values:
-                with self.assertRaises(OverflowError):
+                debug_info = {'value': value, 'rounding': time_rnd}
+                with self.assertRaises(OverflowError, msg=debug_info):
                     pytime_converter(value, time_rnd)
 
     def check_int_rounding(self, pytime_converter, expected_func,
index c82d5985b4783daf127c02fecdf9e3512c079e50..1b20dc797ece8249c5565107de15ece312c77e1a 100644 (file)
@@ -7,6 +7,11 @@
 #include <mach/mach_time.h>   /* mach_absolute_time(), mach_timebase_info() */
 #endif
 
+#define _PyTime_check_mul_overflow(a, b) \
+    (assert(b > 0), \
+     (_PyTime_t)(a) < _PyTime_MIN / (_PyTime_t)(b) \
+     || _PyTime_MAX / (_PyTime_t)(b) < (_PyTime_t)(a))
+
 /* To millisecond (10^-3) */
 #define SEC_TO_MS 1000
 
@@ -226,12 +231,15 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise)
     _PyTime_t t;
     int res = 0;
 
-    t = (_PyTime_t)ts->tv_sec * SEC_TO_NS;
-    if (t / SEC_TO_NS != ts->tv_sec) {
+    assert(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
+    t = (_PyTime_t)ts->tv_sec;
+
+    if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
         if (raise)
             _PyTime_overflow();
         res = -1;
     }
+    t = t * SEC_TO_NS;
 
     t += ts->tv_nsec;
 
@@ -245,12 +253,15 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise)
     _PyTime_t t;
     int res = 0;
 
-    t = (_PyTime_t)tv->tv_sec * SEC_TO_NS;
-    if (t / SEC_TO_NS != tv->tv_sec) {
+    assert(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
+    t = (_PyTime_t)tv->tv_sec;
+
+    if (_PyTime_check_mul_overflow(t, SEC_TO_NS)) {
         if (raise)
             _PyTime_overflow();
         res = -1;
     }
+    t = t * SEC_TO_NS;
 
     t += (_PyTime_t)tv->tv_usec * US_TO_NS;
 
@@ -308,11 +319,11 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round,
             return -1;
         }
 
-        *t = sec * unit_to_ns;
-        if (*t / unit_to_ns != sec) {
+        if (_PyTime_check_mul_overflow(sec, unit_to_ns)) {
             _PyTime_overflow();
             return -1;
         }
+        *t = sec * unit_to_ns;
         return 0;
     }
 }
@@ -587,19 +598,20 @@ _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
     return pygettimeofday_new(t, info, 1);
 }
 
-
 static int
 pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
 {
 #if defined(MS_WINDOWS)
-    ULONGLONG result;
+    ULONGLONG ticks;
+    _PyTime_t t;
 
     assert(info == NULL || raise);
 
-    result = GetTickCount64();
+    ticks = GetTickCount64();
+    assert(sizeof(result) <= sizeof(_PyTime_t));
+    t = (_PyTime_t)ticks;
 
-    *tp = result * MS_TO_NS;
-    if (*tp / MS_TO_NS != result) {
+    if (_PyTime_check_mul_overflow(t, MS_TO_NS)) {
         if (raise) {
             _PyTime_overflow();
             return -1;
@@ -607,6 +619,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
         /* Hello, time traveler! */
         assert(0);
     }
+    *tp = t * MS_TO_NS;
 
     if (info) {
         DWORD timeAdjustment, timeIncrement;