[tor-commits] [tor/master] Fix an integer overflow related to monotonic time on windows.

nickm at torproject.org nickm at torproject.org
Tue Jul 26 15:33:08 UTC 2016


commit d97fca16d0b37723c2cbe2bacf86601af0e24805
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Jul 26 11:23:58 2016 -0400

    Fix an integer overflow related to monotonic time on windows.
    
    To maintain precision, to get nanoseconds, we were multiplying our
    tick count by a billion, then dividing by ticks-per-second.  But
    that apparently isn't such a great idea, since ticks-per-second is
    sometimes a billion on its own, so our intermediate result was
    giving us attoseconds.
    
    When you're counting in attoseconds, you can only fit about 9
    seconds into an int64_t, which is not so great for our purposes.
    
    Instead, we now simplify the 1000000000/1000000000 fraction before
    we start messing with nanoseconds.  This has potential to mess us
    up if some future MS version declares that performance counters will
    use 1,000,000,007 units per second, but let's burn that bridge when
    we come to it.
---
 src/common/compat_time.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 4757225..7676e3a 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -374,8 +374,10 @@ monotime_diff_nsec(const monotime_t *start,
 /* end of "HAVE_CLOCK_GETTIME" */
 #elif defined (_WIN32)
 
-/** Result of QueryPerformanceFrequency, as an int64_t. */
-static int64_t ticks_per_second = 0;
+/** Result of QueryPerformanceFrequency, in terms needed to
+ * convert ticks to nanoseconds. */
+static int64_t nsec_per_tick_numer = 1;
+static int64_t nsec_per_tick_denom = 1;
 
 /** Lock to protect last_pctr and pctr_offset */
 static CRITICAL_SECTION monotime_lock;
@@ -397,7 +399,17 @@ monotime_init_internal(void)
   ok = QueryPerformanceFrequency(&li);
   tor_assert(ok);
   tor_assert(li.QuadPart);
-  ticks_per_second = li.QuadPart;
+
+  uint64_t n = ONE_BILLION;
+  uint64_t d = li.QuadPart;
+  /* We need to simplify this or we'll probably overflow the int64. */
+  simplify_fraction64(&n, &d);
+  tor_assert(n <= INT64_MAX);
+  tor_assert(d <= INT64_MAX);
+
+  nsec_per_tick_numer = (int64_t) n;
+  nsec_per_tick_denom = (int64_t) d;
+
   last_pctr = 0;
   pctr_offset = 0;
 
@@ -418,7 +430,8 @@ monotime_get(monotime_t *out)
 
 #ifdef TOR_UNIT_TESTS
   if (monotime_mocking_enabled) {
-    out->pcount_ = (mock_time_nsec * ticks_per_second) / ONE_BILLION;
+    out->pcount_ = (mock_time_nsec * nsec_per_tick_denom)
+      / nsec_per_tick_numer;
     return;
   }
 #endif
@@ -465,7 +478,7 @@ monotime_diff_nsec(const monotime_t *start,
     monotime_init();
   }
   const int64_t diff_ticks = end->pcount_ - start->pcount_;
-  return (diff_ticks * ONE_BILLION) / ticks_per_second;
+  return (diff_ticks * nsec_per_tick_numer) / nsec_per_tick_denom;
 }
 
 int64_t





More information about the tor-commits mailing list