summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2020-06-11 09:38:44 +0200
committerGitHub <noreply@github.com>2020-06-11 09:38:44 +0200
commitc4dd866a15744fc6df8b7abb8a0af77612d28b2e (patch)
tree71018e04f4b198153644b1e0fd8a167910789c14
parent7217a7edbd6beb265b3232953cbeaa9dcea62414 (diff)
parentdb9fa8816056b367a5d97f57c2498241aaef974a (diff)
Merge pull request #38958 from lawnjelly/time_overflow_4
Fix overflow condition with QueryPerformanceCounter
-rw-r--r--platform/uwp/os_uwp.cpp21
-rw-r--r--platform/windows/os_windows.cpp21
2 files changed, 38 insertions, 4 deletions
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 7bd67d3726..ee25754704 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -535,11 +535,28 @@ void OS_UWP::delay_usec(uint32_t p_usec) const {
uint64_t OS_UWP::get_ticks_usec() const {
uint64_t ticks;
- uint64_t time;
+
// This is the number of clock ticks since start
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+
// Divide by frequency to get the time in seconds
- time = ticks * 1000000L / ticks_per_second;
+ // original calculation shown below is subject to overflow
+ // with high ticks_per_second and a number of days since the last reboot.
+ // time = ticks * 1000000L / ticks_per_second;
+
+ // we can prevent this by either using 128 bit math
+ // or separating into a calculation for seconds, and the fraction
+ uint64_t seconds = ticks / ticks_per_second;
+
+ // compiler will optimize these two into one divide
+ uint64_t leftover = ticks % ticks_per_second;
+
+ // remainder
+ uint64_t time = (leftover * 1000000L) / ticks_per_second;
+
+ // seconds
+ time += seconds * 1000000L;
+
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 0dab0c601a..29eabfdde8 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -403,12 +403,29 @@ void OS_Windows::delay_usec(uint32_t p_usec) const {
uint64_t OS_Windows::get_ticks_usec() const {
uint64_t ticks;
- uint64_t time;
+
// This is the number of clock ticks since start
if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks))
ticks = (UINT64)timeGetTime();
+
// Divide by frequency to get the time in seconds
- time = ticks * 1000000L / ticks_per_second;
+ // original calculation shown below is subject to overflow
+ // with high ticks_per_second and a number of days since the last reboot.
+ // time = ticks * 1000000L / ticks_per_second;
+
+ // we can prevent this by either using 128 bit math
+ // or separating into a calculation for seconds, and the fraction
+ uint64_t seconds = ticks / ticks_per_second;
+
+ // compiler will optimize these two into one divide
+ uint64_t leftover = ticks % ticks_per_second;
+
+ // remainder
+ uint64_t time = (leftover * 1000000L) / ticks_per_second;
+
+ // seconds
+ time += seconds * 1000000L;
+
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;