From 7fdc5b452845a2dc7ec2f1dad53a973515a9dd82 Mon Sep 17 00:00:00 2001 From: QRMOE Date: Sun, 11 Oct 2026 15:51:43 +0200 Subject: [PATCH 1/2] fix(libkernel): honor null clock_getres output Return success for a null POSIX resolution output before inspecting the clock ID, matching FreeBSD 11.4 sys_clock_getres. AI-assisted: yes --- core/libs/prx/libkernel/Time/Time.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/libs/prx/libkernel/Time/Time.cpp b/core/libs/prx/libkernel/Time/Time.cpp index 581e81bb5..0f86dbf4d 100644 --- a/core/libs/prx/libkernel/Time/Time.cpp +++ b/core/libs/prx/libkernel/Time/Time.cpp @@ -473,8 +473,7 @@ int APS5_VABI gettimeofday_nid_postfix(KernelTimeval* tv, KernelTimezone* tz) { } int APS5_VABI clock_getres_nid_postfix(int clockId, KernelTimespec* res) { - KernelTimespec ignoredResolution{}; - if (res == nullptr) res = &ignoredResolution; + if (res == nullptr) return 0; if (IsCpuClock(clockId)) return clock_getres_nid_postfix(GUEST_CLOCK_THREAD_CPUTIME_ID, res); if (clockId == 1 || clockId == 2) { From 10e822cf04763c1b20e39848cb5f975eb7792f2b Mon Sep 17 00:00:00 2001 From: QRMOE Date: Sun, 11 Oct 2026 15:53:15 +0200 Subject: [PATCH 2/2] test(libkernel): cover omitted clock resolution Cover 20 clock IDs, preserved guest errno, non-null unsupported clocks and the SCE null-output fault. The regression fails against main and passes with the accompanying fix. AI-assisted: yes --- core/libs/tests/GuestFreebsdClocks.cpp | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core/libs/tests/GuestFreebsdClocks.cpp b/core/libs/tests/GuestFreebsdClocks.cpp index be5f30434..d75ca2ec4 100644 --- a/core/libs/tests/GuestFreebsdClocks.cpp +++ b/core/libs/tests/GuestFreebsdClocks.cpp @@ -1,13 +1,17 @@ #include "SceTypes.hpp" #include +#include #include +#include #include +#include extern "C" { int APS5_VABI clock_gettime_nid_postfix(int clockId, KernelTimespec* tp); int APS5_VABI clock_getres_nid_postfix(int clockId, KernelTimespec* res); int APS5_VABI sceKernelClockGettime(KernelClockid clockId, KernelTimespec* tp); int APS5_VABI sceKernelClockGetres(KernelClockid clockId, KernelTimespec* tp); +int* APS5_VABI __error_nid_postfix(); int APS5_VABI sceKernelUsleep_nid_postfix(KernelUseconds microseconds); int APS5_VABI gettimeofday_nid_postfix(KernelTimeval* tv, KernelTimezone* tz); std::int64_t APS5_VABI _Xtime_get_ticks_nid_postfix(); @@ -32,6 +36,34 @@ static constexpr std::int64_t GIVE_UP_NANOS = 10 * NANOS_PER_SECOND; static void Require(bool value) { if (!value) std::abort(); } +static bool OmittedResolutionSucceeds() { + constexpr int clocks[] = {0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 3, 6, 9999, -1, INT_MIN, INT_MAX}; + for (const int clock : clocks) { + *__error_nid_postfix() = 77; + try { + if (clock_getres_nid_postfix(clock, nullptr) == SCE_OK && *__error_nid_postfix() == 77) continue; + } catch (const std::runtime_error&) { + } + std::fprintf(stderr, "clock_getres(%d, nullptr) must succeed without changing errno\n", clock); + return false; + } + return true; +} + +static void UnsupportedResolutionStillThrows() { + KernelTimespec resolution{-1, -1}; + bool rejected = false; + try { + clock_getres_nid_postfix(3, &resolution); + } catch (const std::runtime_error&) { + rejected = true; + } + Require(rejected && resolution.tv_sec == -1 && resolution.tv_nsec == -1); + constexpr int fault = static_cast(0x8002000eu); + Require(sceKernelClockGetres(GUEST_CLOCK_REALTIME, nullptr) == fault); + Require(sceKernelClockGetres(3, nullptr) == fault); +} + static KernelTimespec Read(int clockId) { KernelTimespec time{-1, -1}; Require(clock_gettime_nid_postfix(clockId, &time) == SCE_OK); @@ -168,6 +200,8 @@ static void CalendarConversionsInitializeTheirState() { } int main() { + if (!OmittedResolutionSucceeds()) return 1; + UnsupportedResolutionStillThrows(); CalendarConversionsInitializeTheirState(); SecondClockReportsWholeSeconds(); KernelTimezone zone{-1, -1};