From 0a520ced919858ec8360c2d4f8cba20cbd133cd2 Mon Sep 17 00:00:00 2001 From: Disaster Date: Sat, 31 Oct 2026 19:58:28 +0100 Subject: [PATCH] feat(libSceNpCommon): null-check sceNpGetSystemClockUsec Co-Authored-By: Claude Sonnet 5.5 --- core/libs/prx/libSceNpCommon/Export.cpp | 1 + core/libs/tests/GuestNpCommon.cpp | 3 +++ docs/dev/debt/libSceNpCommon.md | 1 + 3 files changed, 5 insertions(+) diff --git a/core/libs/prx/libSceNpCommon/Export.cpp b/core/libs/prx/libSceNpCommon/Export.cpp index 77a7b33fc9..d32ce8ed7c 100644 --- a/core/libs/prx/libSceNpCommon/Export.cpp +++ b/core/libs/prx/libSceNpCommon/Export.cpp @@ -157,6 +157,7 @@ int APS5_VABI sceNpJoinThread(Pthread thread, void** retval) { } int APS5_VABI sceNpGetSystemClockUsec(std::int64_t* usec) { + if (usec == nullptr) return NP_ERROR_INVALID_ARGUMENT; KernelTimespec now{}; const int result = sceKernelClockGettime(CLOCK_MONOTONIC_ID, &now); if (result == 0) *usec = now.tv_sec * 1000000 + now.tv_nsec / 1000; diff --git a/core/libs/tests/GuestNpCommon.cpp b/core/libs/tests/GuestNpCommon.cpp index 21e7c42392..08313861e1 100644 --- a/core/libs/tests/GuestNpCommon.cpp +++ b/core/libs/tests/GuestNpCommon.cpp @@ -132,6 +132,9 @@ static int testClock() { bool ok = expect(sceNpGetSystemClockUsec(&usec) == 0, "the clock was not read"); sceKernelClockGettime(4, &after); + ok &= expect(sceNpGetSystemClockUsec(nullptr) == INVALID_ARGUMENT, "a null destination was not rejected"); + std::int64_t later = -1; + ok &= expect(sceNpGetSystemClockUsec(&later) == 0 && later >= usec && usec >= 0, "the clock went backwards"); ok &= expect(usec >= before.tv_sec * 1000000 + before.tv_nsec / 1000 && usec <= after.tv_sec * 1000000 + after.tv_nsec / 1000, "the clock is not the monotonic kernel clock in microseconds"); char version[12]; diff --git a/docs/dev/debt/libSceNpCommon.md b/docs/dev/debt/libSceNpCommon.md index 0e1d98b320..8d62a98e68 100644 --- a/docs/dev/debt/libSceNpCommon.md +++ b/docs/dev/debt/libSceNpCommon.md @@ -35,6 +35,7 @@ Pending import declarations are matched to names in the local libSceNpCommon.spr - [Online ID and NpId utilities](../../../core/libs/prx/libSceNpCommon/Export.cpp) (libSceNpCommon) - `sceNpCmpOnlineId`, `sceNpCmpNpIdInOrder`, `sceNpGetPlatformType` and `sceNpIntIsValidOnlineId` are not measured on a console; their signatures, checks and results follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/a808e76/src/core/libraries/np/np_common.cpp), including the platform tags read from `opt[4..7]` and the 3 to 16 character online ID rule. - [Mutex, condition and thread wrappers](../../../core/libs/prx/libSceNpCommon/Export.cpp) (libSceNpCommon) - the `sceNpMutex*`, `sceNpLwMutex*`, `sceNpCond*` and `sceNpJoinThread` wrappers forward to the libkernel `scePthread*` calls as in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/a808e76/src/core/libraries/np/np_common.cpp) and are not measured on a console. Only `EBUSY` from try-lock and `ETIMEDOUT` from a timed wait are mapped to NP errors; every other kernel error is returned unchanged. The `flags` argument of `sceNpCondInit` is ignored. +- [sceNpGetSystemClockUsec](../../../core/libs/prx/libSceNpCommon/Export.cpp) (libSceNpCommon) - a null destination returns the invalid-argument error `0x80550003` as a host-safety fallback; shadPS4 writes through the pointer without checking it, and the console behaviour is not measured. - [sceNpGetSdkVersion](../../../core/libs/prx/libSceNpCommon/Export.cpp) (libSceNpCommon) - writes the libkernel system software version as `major.minor` into an 8-byte buffer without checking it, as shadPS4 does; that version is the fixed `1.00`, not the SDK version a title was built with. - [The exports in Runtime.cpp](../../../core/libs/prx/libSceNpCommon/Runtime.cpp) and [Strings.cpp](../../../core/libs/prx/libSceNpCommon/Strings.cpp) follow `libSceNpCommon.sprx` from firmware 13.60, read from disassembly and not measured on a console. - [The sce::np::Object new and delete operators](../../../core/libs/prx/libSceNpCommon/Runtime.cpp) (libSceNpCommon) - do not check that the size plus their 16-byte header fits, and free through the allocator stored in that header, ignoring the allocator passed to the delete forms, as `libSceNpCommon.sprx` of firmware 13.60 does, read from disassembly, not measured on a console. The extended forms keep the address of the `SceNpAllocatorEx` itself, whose first member is the allocator.