Merge pull request #38958 from lawnjelly/time_overflow_4

Fix overflow condition with QueryPerformanceCounter
This commit is contained in:
Rémi Verschelde 2020-06-11 09:38:44 +02:00 committed by GitHub
commit c4dd866a15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 4 deletions

View File

@ -535,11 +535,28 @@ void OS_UWP::delay_usec(uint32_t p_usec) const {
uint64_t OS_UWP::get_ticks_usec() const { uint64_t OS_UWP::get_ticks_usec() const {
uint64_t ticks; uint64_t ticks;
uint64_t time;
// This is the number of clock ticks since start // This is the number of clock ticks since start
QueryPerformanceCounter((LARGE_INTEGER *)&ticks); QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
// Divide by frequency to get the time in seconds // 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 // Subtract the time at game start to get
// the time since the game started // the time since the game started
time -= ticks_start; time -= ticks_start;

View File

@ -403,12 +403,29 @@ void OS_Windows::delay_usec(uint32_t p_usec) const {
uint64_t OS_Windows::get_ticks_usec() const { uint64_t OS_Windows::get_ticks_usec() const {
uint64_t ticks; uint64_t ticks;
uint64_t time;
// This is the number of clock ticks since start // This is the number of clock ticks since start
if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks)) if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks))
ticks = (UINT64)timeGetTime(); ticks = (UINT64)timeGetTime();
// Divide by frequency to get the time in seconds // 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 // Subtract the time at game start to get
// the time since the game started // the time since the game started
time -= ticks_start; time -= ticks_start;