diff options
author | Jonathan Peyton <jonathan.l.peyton@intel.com> | 2018-12-13 23:18:55 +0000 |
---|---|---|
committer | Jonathan Peyton <jonathan.l.peyton@intel.com> | 2018-12-13 23:18:55 +0000 |
commit | bdb0a2ffaa18ea494ce81c32cb4454ad57735946 (patch) | |
tree | ddb450f7d71fe1a32217360a605744420eb84ce3 /openmp | |
parent | 6d88e049dc51be8a9ba2e853e17fdf8c4fa6026b (diff) | |
download | llvm-bdb0a2ffaa18ea494ce81c32cb4454ad57735946.zip llvm-bdb0a2ffaa18ea494ce81c32cb4454ad57735946.tar.gz llvm-bdb0a2ffaa18ea494ce81c32cb4454ad57735946.tar.bz2 |
[OpenMP] Fix transient divide by zero bug in 32-bit code
The value returned by __kmp_now_nsec() can overflow 32-bit values causing
incorrect values to be returned. The overflow can end up causing a divide
by zero error because in __kmp_initialize_system_tick(), the value
(__kmp_now_nsec() - nsec) can end up being much larger than the numerator:
1e6 * (delay + (now - goal))
during a pathological timing where the current time calculated is much larger
than nsec. When this happens, the value of __kmp_ticks_per_msec is set to zero
which is then used as the denominator in the KMP_NOW_MSEC() macro leading to
the divide by zero error.
Differential Revision: https://reviews.llvm.org/D55300
llvm-svn: 349090
Diffstat (limited to 'openmp')
-rw-r--r-- | openmp/runtime/src/z_Linux_util.cpp | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/openmp/runtime/src/z_Linux_util.cpp b/openmp/runtime/src/z_Linux_util.cpp index c2f37eb..aa0302c 100644 --- a/openmp/runtime/src/z_Linux_util.cpp +++ b/openmp/runtime/src/z_Linux_util.cpp @@ -1935,20 +1935,27 @@ void __kmp_elapsed_tick(double *t) { *t = 1 / (double)CLOCKS_PER_SEC; } kmp_uint64 __kmp_now_nsec() { struct timeval t; gettimeofday(&t, NULL); - return KMP_NSEC_PER_SEC * t.tv_sec + 1000 * t.tv_usec; + kmp_uint64 nsec = (kmp_uint64)KMP_NSEC_PER_SEC * (kmp_uint64)t.tv_sec + + (kmp_uint64)1000 * (kmp_uint64)t.tv_usec; + return nsec; } #if KMP_ARCH_X86 || KMP_ARCH_X86_64 /* Measure clock ticks per millisecond */ void __kmp_initialize_system_tick() { + kmp_uint64 now, nsec2, diff; kmp_uint64 delay = 100000; // 50~100 usec on most machines. kmp_uint64 nsec = __kmp_now_nsec(); kmp_uint64 goal = __kmp_hardware_timestamp() + delay; - kmp_uint64 now; while ((now = __kmp_hardware_timestamp()) < goal) ; - __kmp_ticks_per_msec = - (kmp_uint64)(1e6 * (delay + (now - goal)) / (__kmp_now_nsec() - nsec)); + nsec2 = __kmp_now_nsec(); + diff = nsec2 - nsec; + if (diff > 0) { + kmp_uint64 tpms = (kmp_uint64)(1e6 * (delay + (now - goal)) / diff); + if (tpms > 0) + __kmp_ticks_per_msec = tpms; + } } #endif |