I was playing S3DNA on steam and it froze after running for about 4 days. I gathered the following information using a debugger:
curtime = 0x1492f94f
lasttimecount = 0x0170b02b
delay = 3681400541 ms (~42.6 days)
The offending line in 1.3.3 is this one, where lasttimecount is an int32_t. That multiplication overflows after 2**31 / 100 tics (~3.6 days).
|
SDL_Delay(((lasttimecount + 1) * 100) / 7 - curtime); |
From what I can tell this is still relevant in the master branch, though TICS2MS somewhat mitigates this by using uint32_t, making the overflow occur after 2**32 / 100 tics (~7.1 days)
|
SDL_Delay(TICS2MS(lasttimecount + 1) - curtime); |
However, there's also this check:
|
// Detect rollover, particularly if the game were paused for a LONG time |
|
if(lasttimecount > GetTimeCount()) |
|
ResetTimeCount(); |
In vanilla this was meant to deal with a slightly different kind of rollover (
TimeCount incrementing), but here it, perhaps unintentionally, manages to detect the rollover caused by 32-bit multiplication overflow in
MS2TICS. It may seem that this check would also prevent an overflow in
TICS2MS(lasttimecount + 1), but there's actually an edge case due to the
+ 1. Here's a example that, from what I can tell, would freeze the latest version of ecwolf:
curtime = 0x24924918 (the rollover is not detected until 0x24924925)
lasttimecount = 0x028f5c28
delay = 3681400552 ms (~42.6 days)
So, tl;dr, this does seem like it can happen on newer builds.
The easiest solution is to use uint64_t/SDL_GetTicks64 everywhere, since it takes millions of years to overflow.
I was playing S3DNA on steam and it froze after running for about 4 days. I gathered the following information using a debugger:
The offending line in 1.3.3 is this one, where
lasttimecountis an int32_t. That multiplication overflows after 2**31 / 100 tics (~3.6 days).ECWolf/src/wl_draw.cpp
Line 726 in d715e0a
From what I can tell this is still relevant in the master branch, though
TICS2MSsomewhat mitigates this by using uint32_t, making the overflow occur after 2**32 / 100 tics (~7.1 days)ECWolf/src/wl_play.cpp
Line 219 in 1bff92d
However, there's also this check:
ECWolf/src/wl_play.cpp
Lines 210 to 212 in 1bff92d
In vanilla this was meant to deal with a slightly different kind of rollover (
TimeCountincrementing), but here it, perhaps unintentionally, manages to detect the rollover caused by 32-bit multiplication overflow inMS2TICS. It may seem that this check would also prevent an overflow inTICS2MS(lasttimecount + 1), but there's actually an edge case due to the+ 1. Here's a example that, from what I can tell, would freeze the latest version of ecwolf:So, tl;dr, this does seem like it can happen on newer builds.
The easiest solution is to use uint64_t/SDL_GetTicks64 everywhere, since it takes millions of years to overflow.