summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2016-07-26 11:23:58 -0400
committerNick Mathewson <nickm@torproject.org>2016-07-26 11:23:58 -0400
commitd97fca16d0b37723c2cbe2bacf86601af0e24805 (patch)
tree77b65a2a9ff7bfaf6a0d0e331e18f08e8b9a1aa7
parent09c25697d74cdfdefe5fa365e4691cc9401e2129 (diff)
downloadtor-d97fca16d0b37723c2cbe2bacf86601af0e24805.tar.gz
tor-d97fca16d0b37723c2cbe2bacf86601af0e24805.zip
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.
-rw-r--r--src/common/compat_time.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 4757225404..7676e3a0e5 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