coreinit: Time to tick conversion is unsigned

The result is treated as signed in most cases, but the calculation uses unsigned arithmetic.

As a concrete example where this matters, DS VC passes -1 (2^64-1) to OSWaitEventWithTimeout which internally causes an overflow. But only with unsigned arithmetic this will result in a large positive number that behaves like the intended infinite timeout. With signed arithmetic the result is negative and the events will timeout immediately.
This commit is contained in:
Exzap 2025-01-30 03:32:24 +01:00
parent e834515f43
commit c714e8cb6b
2 changed files with 5 additions and 7 deletions

View file

@ -73,8 +73,6 @@ namespace coreinit
}
}
uint64 coreinit_getOSTime();
bool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout)
{
__OSLockScheduler();
@ -95,14 +93,14 @@ namespace coreinit
// workaround for a bad implementation in some Unity games (like Qube Directors Cut, see FEventWiiU::Wait)
// where the the return value of OSWaitEventWithTimeout is ignored and instead the game measures the elapsed time to determine if a timeout occurred
if (timeout < 0x00FFFFFFFFFFFFFFULL)
timeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout)
WaitEventWithTimeoutData data;
data.thread = OSGetCurrentThread();
data.threadQueue = &event->threadQueue;
data.hasTimeout = false;
auto hostAlarm = coreinit::OSHostAlarmCreate(coreinit::coreinit_getOSTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data);
auto hostAlarm = coreinit::OSHostAlarmCreate(OSGetTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data);
event->threadQueue.queueAndWait(OSGetCurrentThread());
coreinit::OSHostAlarmDestroy(hostAlarm);
if (data.hasTimeout)

View file

@ -40,12 +40,12 @@ namespace coreinit
inline TimerTicks ConvertNsToTimerTicks(uint64 ns)
{
return ((GetTimerClock() / 31250LL) * ((TimerTicks)ns) / 32000LL);
return static_cast<TimerTicks>((static_cast<uint64>(GetTimerClock()) / 31250ULL) * (ns) / 32000ULL);
}
inline TimerTicks ConvertMsToTimerTicks(uint64 ms)
{
return (TimerTicks)ms * GetTimerClock() / 1000LL;
return static_cast<TimerTicks>(ms * static_cast<uint64>(GetTimerClock()) / 1000ULL);
}
};