[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