From b0414440a345143864d2b87c3fd73bedafd4c007 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 25 Feb 2026 10:21:20 -0800 Subject: [PATCH] Fixed timer overflow on some platforms We have an implementation that uses 128-bit math and one that handles large values without it (thanks @jessechounard and @rabbit-ecl!) Fixes https://github.com/libsdl-org/SDL/issues/15042 (cherry picked from commit 24404d9047160577e82f71825ee85d988c0c5113) --- src/timer/SDL_timer.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/timer/SDL_timer.c b/src/timer/SDL_timer.c index ebc8648713..9bd3da408f 100644 --- a/src/timer/SDL_timer.c +++ b/src/timer/SDL_timer.c @@ -535,11 +535,20 @@ bool SDL_RemoveTimer(SDL_TimerID id) #endif // !SDL_PLATFORM_EMSCRIPTEN +#ifdef USE_128BIT_MATH +typedef unsigned __int128 Uint128; +#endif + static Uint64 tick_start; +#ifdef USE_128BIT_MATH +static Uint128 tick_numerator_ns; +static Uint128 tick_numerator_ms; +#else static Uint32 tick_numerator_ns; static Uint32 tick_denominator_ns; static Uint32 tick_numerator_ms; static Uint32 tick_denominator_ms; +#endif #if defined(SDL_TIMER_WINDOWS) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) #include @@ -583,7 +592,9 @@ static void SDLCALL SDL_TimerResolutionChanged(void *userdata, const char *name, void SDL_InitTicks(void) { Uint64 tick_freq; +#ifndef USE_128BIT_MATH Uint32 gcd; +#endif if (tick_start) { return; @@ -597,6 +608,10 @@ void SDL_InitTicks(void) tick_freq = SDL_GetPerformanceFrequency(); SDL_assert(tick_freq > 0 && tick_freq <= (Uint64)SDL_MAX_UINT32); +#ifdef USE_128BIT_MATH + tick_numerator_ns = ((Uint128)SDL_NS_PER_SECOND << 32) / tick_freq; + tick_numerator_ms = ((Uint128)SDL_MS_PER_SECOND << 32) / tick_freq; +#else gcd = SDL_CalculateGCD(SDL_NS_PER_SECOND, (Uint32)tick_freq); tick_numerator_ns = (SDL_NS_PER_SECOND / gcd); tick_denominator_ns = (Uint32)(tick_freq / gcd); @@ -604,6 +619,7 @@ void SDL_InitTicks(void) gcd = SDL_CalculateGCD(SDL_MS_PER_SECOND, (Uint32)tick_freq); tick_numerator_ms = (SDL_MS_PER_SECOND / gcd); tick_denominator_ms = (Uint32)(tick_freq / gcd); +#endif tick_start = SDL_GetPerformanceCounter(); if (!tick_start) { @@ -630,9 +646,12 @@ Uint64 SDL_GetTicksNS(void) } starting_value = (SDL_GetPerformanceCounter() - tick_start); - value = (starting_value * tick_numerator_ns); - SDL_assert(value >= starting_value); - value /= tick_denominator_ns; +#ifdef USE_128BIT_MATH + value = (Uint64)(((Uint128)starting_value * tick_numerator_ns) >> 32); +#else + value = (starting_value / tick_denominator_ns) * tick_numerator_ns + + (starting_value % tick_denominator_ns) * tick_numerator_ns / tick_denominator_ns; +#endif return value; } @@ -645,9 +664,12 @@ Uint64 SDL_GetTicks(void) } starting_value = (SDL_GetPerformanceCounter() - tick_start); - value = (starting_value * tick_numerator_ms); - SDL_assert(value >= starting_value); - value /= tick_denominator_ms; +#ifdef USE_128BIT_MATH + value = (Uint64)(((Uint128)starting_value * tick_numerator_ms) >> 32); +#else + value = (starting_value / tick_denominator_ms) * tick_numerator_ms + + (starting_value % tick_denominator_ms) * tick_numerator_ms / tick_denominator_ms; +#endif return value; }