[llvm-branch-commits] [libcxx] 579d0dc - [libcxx] Avoid overflows in the windows __libcpp_steady_clock_now()

Tobias Hieta via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Feb 1 05:10:13 PST 2021


Author: Martin Storsjö
Date: 2021-02-01T14:09:23+01:00
New Revision: 579d0dc25dcd72e0a0a1411426c921cf01bfefe3

URL: https://github.com/llvm/llvm-project/commit/579d0dc25dcd72e0a0a1411426c921cf01bfefe3
DIFF: https://github.com/llvm/llvm-project/commit/579d0dc25dcd72e0a0a1411426c921cf01bfefe3.diff

LOG: [libcxx] Avoid overflows in the windows __libcpp_steady_clock_now()

As freq.QuadValue can be in the range of 10000000 to 19200000,
the multiplication before division makes the calculation overflow
and wrap to negative values every 16-30 minutes.

Instead count the whole seconds separately before adding the
scaled fractional seconds.

Add a testcase for steady_clock to check that the values returned for
now() compare as bigger than the zero time origin; this
corresponds to a testcase in Qt [1] [2] (that failed spuriously
due to this).

[1] https://bugreports.qt.io/browse/QTBUG-89539
[2] https://code.qt.io/cgit/qt/qtbase.git/tree/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp?id=f8de5e54022b8b7471131b7ad55c83b69b2684c0#n569

Differential Revision: https://reviews.llvm.org/D93456

Added: 
    

Modified: 
    libcxx/src/chrono.cpp
    libcxx/test/std/utilities/time/time.clock/time.clock.steady/now.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/src/chrono.cpp b/libcxx/src/chrono.cpp
index 1419cf2f74a8..5291d4fa8dc6 100644
--- a/libcxx/src/chrono.cpp
+++ b/libcxx/src/chrono.cpp
@@ -153,7 +153,10 @@ static steady_clock::time_point __libcpp_steady_clock_now() {
 
   LARGE_INTEGER counter;
   (void) QueryPerformanceCounter(&counter);
-  return steady_clock::time_point(steady_clock::duration(counter.QuadPart * nano::den / freq.QuadPart));
+  auto seconds = counter.QuadPart / freq.QuadPart;
+  auto fractions = counter.QuadPart % freq.QuadPart;
+  auto dur = seconds * nano::den + fractions * nano::den / freq.QuadPart;
+  return steady_clock::time_point(steady_clock::duration(dur));
 }
 
 #elif defined(CLOCK_MONOTONIC)

diff  --git a/libcxx/test/std/utilities/time/time.clock/time.clock.steady/now.pass.cpp b/libcxx/test/std/utilities/time/time.clock/time.clock.steady/now.pass.cpp
index 4b8104dd1a6f..14dc9a9832dc 100644
--- a/libcxx/test/std/utilities/time/time.clock/time.clock.steady/now.pass.cpp
+++ b/libcxx/test/std/utilities/time/time.clock/time.clock.steady/now.pass.cpp
@@ -25,6 +25,8 @@ int main(int, char**)
     C::time_point t1 = C::now();
     C::time_point t2 = C::now();
     assert(t2 >= t1);
+    // make sure t2 didn't wrap around
+    assert(t2 > std::chrono::time_point<C>());
 
   return 0;
 }


        


More information about the llvm-branch-commits mailing list