mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-01 12:45:56 +00:00
fix(libSceRtc): range-check the precise RFC 3339 formatters as measured on a PS5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
895f47f4ee
commit
10013d1e08
3 files changed
+42
-5
No files matched your search
@@ -759,9 +759,17 @@ int APS5_VABI sceRtcFormatRFC3339Precise(char* date_time, const RtcTick* utc, in
|
||||
utc = &now;
|
||||
}
|
||||
if (time_zone_minutes < -1439 || time_zone_minutes > 1439 || precision < 0 || precision > 6) return SCE_RTC_ERROR_INVALID_VALUE;
|
||||
RtcTick local{};
|
||||
if (const int result = addTicks(&local, utc, time_zone_minutes, TICKS_PER_MINUTE); result != 0) return result;
|
||||
const RtcDateTime time = fromTick(local.tick);
|
||||
const std::uint64_t shift = static_cast<std::uint64_t>(time_zone_minutes < 0 ? -time_zone_minutes : time_zone_minutes) * TICKS_PER_MINUTE;
|
||||
std::uint64_t localTick = 0;
|
||||
if (time_zone_minutes < 0) {
|
||||
if (utc->tick < shift) return SCE_RTC_ERROR_INVALID_VALUE;
|
||||
localTick = utc->tick - shift;
|
||||
} else {
|
||||
if (utc->tick > MAX_TICK || MAX_TICK - utc->tick < shift) return SCE_RTC_ERROR_INVALID_YEAR;
|
||||
localTick = utc->tick + shift;
|
||||
}
|
||||
if (localTick > MAX_TICK) return SCE_RTC_ERROR_INVALID_YEAR;
|
||||
const RtcDateTime time = fromTick(localTick);
|
||||
int written = std::snprintf(date_time, 20, "%04u-%02u-%02uT%02u:%02u:%02u", time.year, time.month, time.day, time.hour, time.minute, time.second);
|
||||
if (precision != 0) {
|
||||
std::uint32_t divisor = 1;
|
||||
@@ -785,7 +793,6 @@ int APS5_VABI sceRtcFormatRFC3339PreciseLocalTime(char* date_time, const RtcTick
|
||||
utc = &now;
|
||||
}
|
||||
if (precision < 0 || precision > 6) return SCE_RTC_ERROR_INVALID_VALUE;
|
||||
if (utc->tick > MAX_TICK) return SCE_RTC_ERROR_INVALID_VALUE;
|
||||
return sceRtcFormatRFC3339Precise(date_time, utc, localOffsetMinutes(*utc), precision);
|
||||
}
|
||||
|
||||
|
||||
@@ -883,6 +883,36 @@ int main() {
|
||||
Require(sceRtcFormatRFC3339PreciseLocalTime(precise, &first, 2) == 0 && std::strcmp(precise, "2024-02-29T12:34:56.78Z") == 0);
|
||||
Require(sceRtcFormatRFC3339PreciseLocalTime(precise, &first, 7) == invalidValue);
|
||||
Require(sceRtcFormatRFC3339PreciseLocalTime(nullptr, &first, 0) == invalidPointer);
|
||||
constexpr int invalidYear = static_cast<int>(0x80B50008u);
|
||||
const RtcTick measured{63926543109123456ull};
|
||||
static constexpr const char* fractions[] = {"2026-10-02T13:05:09Z", "2026-10-02T13:05:09.1Z", "2026-10-02T13:05:09.12Z", "2026-10-02T13:05:09.123Z",
|
||||
"2026-10-02T13:05:09.1234Z", "2026-10-02T13:05:09.12345Z", "2026-10-02T13:05:09.123456Z"};
|
||||
for (int digits = 0; digits <= 6; ++digits)
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &measured, 0, digits) == 0 && std::strcmp(precise, fractions[digits]) == 0);
|
||||
struct Zone {
|
||||
int minutes;
|
||||
const char* expected;
|
||||
};
|
||||
static constexpr Zone zones[] = {{60, "2026-10-02T14:05:09.123+01:00"}, {-180, "2026-10-02T10:05:09.123-03:00"}, {330, "2026-10-02T18:35:09.123+05:30"},
|
||||
{-330, "2026-10-02T07:35:09.123-05:30"}, {1439, "2026-10-03T13:04:09.123+23:59"}, {-1439, "2026-10-01T13:06:09.123-23:59"},
|
||||
{1, "2026-10-02T13:06:09.123+00:01"}, {-1, "2026-10-02T13:04:09.123-00:01"}, {720, "2026-10-03T01:05:09.123+12:00"}};
|
||||
for (const auto& zone : zones)
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &measured, zone.minutes, 3) == 0 && std::strcmp(precise, zone.expected) == 0);
|
||||
const RtcTick yearEnd{63934358400999999ull};
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &yearEnd, 1, 6) == 0 && std::strcmp(precise, "2027-01-01T00:01:00.999999+00:01") == 0);
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &yearEnd, -1439, 2) == 0 && std::strcmp(precise, "2026-12-31T00:01:00.99-23:59") == 0);
|
||||
const RtcTick zero{0}, maximum{315537897599999999ull}, pastMaximum{315537897600000000ull}, huge{~0ull}, nines{63926543109999999ull};
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &zero, 0, 6) == 0 && std::strcmp(precise, "0001-01-01T00:00:00.000000Z") == 0);
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &maximum, 0, 6) == 0 && std::strcmp(precise, "9999-12-31T23:59:59.999999Z") == 0);
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &nines, 0, 1) == 0 && std::strcmp(precise, "2026-10-02T13:05:09.9Z") == 0);
|
||||
std::memset(precise, '#', sizeof(precise));
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &zero, -60, 0) == invalidValue && precise[0] == '#');
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &maximum, 60, 6) == invalidYear && precise[0] == '#');
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &pastMaximum, 0, 6) == invalidYear && precise[0] == '#');
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &huge, 0, 6) == invalidYear && precise[0] == '#');
|
||||
Require(sceRtcFormatRFC3339Precise(precise, &pastMaximum, -60, 3) == 0 && std::strcmp(precise, "9999-12-31T23:00:00.000-01:00") == 0);
|
||||
Require(sceRtcFormatRFC3339Precise(nullptr, &measured, 0, 9) == invalidPointer);
|
||||
Require(sceRtcFormatRFC3339PreciseLocalTime(precise, &pastMaximum, 3) == invalidYear);
|
||||
Require(sceRtcCompareTick(&first, &second) == -1 && sceRtcCompareTick(&second, &first) == 1 && sceRtcCompareTick(&first, &first) == 0);
|
||||
Require(sceRtcCompareTick(nullptr, &first) == invalidPointer && sceRtcCompareTick(&first, nullptr) == invalidPointer);
|
||||
RtcTick current{};
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- [sceRtcGetCurrentRawNetworkTick](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - the console reads clock 0x13 and returns its time plus the Unix epoch in ticks, or `0x80B50001` when the clock is unsupported (errno 5). The raw network clock is not modelled; this returns the host clock. Read from the disassembly of libSceRtc.sprx on firmware 13.60, not measured on a console
|
||||
- [sceRtcGetCurrentAdNetworkTick, sceRtcGetCurrentDebugNetworkTick](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - the console reads clocks 0x12 and 0x11 and falls back to network clock 0x10 when either clock is unsupported. These getters use their process-local clock when it was set, otherwise they follow the process-local network clock. The firmware's unsupported-clock result is not modelled. Read from the disassembly of libSceRtc.sprx on firmware 13.60, not measured on a console
|
||||
- [sceRtcSetCurrentTick, sceRtcSetCurrentNetworkTick, sceRtcSetCurrentAdNetworkTick, sceRtcSetCurrentDebugNetworkTick](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - a valid tick sets a process-local clock that advances from a monotonic host clock; the host system clock is not changed. The console sets clock 0, 0x10, 0x12 or 0x11. Null pointers return `0x80B50002` and ticks before the Unix epoch return `0x80B50003`, from disassembly of libSceRtc.sprx on firmware 13.60, not measured on a console. sceRtcSetConf passes its third and fourth arguments to the same clock call with clock 0 and throws; what the pair selects is unknown
|
||||
- [sceRtcFormatRFC3339Precise, sceRtcFormatRFC3339PreciseLocalTime](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - read from the disassembly of libSceRtc.sprx on firmware 13.60: a null tick means the current tick, a precision above 6 or a zone outside -1439 to 1439 minutes returns `0x80B50003`, and the fraction is the microseconds truncated to the requested number of digits. Not compared with console output. The output buffer size is unknown; at most 33 bytes are written
|
||||
- [sceRtcFormatRFC3339Precise, sceRtcFormatRFC3339PreciseLocalTime](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - measured in a payload process on a PS5 (firmware 13.60): a null tick means the current tick, a precision outside 0 to 6 or a zone outside -1439 to 1439 minutes returns `0x80B50003`, the fraction is the microseconds truncated to the requested digits, a local tick before 0001 returns `0x80B50003` and one after 9999 `0x80B50008`, and nothing is written on an error. The local-time variant takes the offset at that tick and checks only the local result, so a tick just past 9999 formats in a zone west of UTC. Here the offset comes from the host's local time, which on Windows has none for years after 3000, so such a tick formats as UTC there. At most 33 bytes are written; the output buffer size is unknown
|
||||
- [sceRtcGetYear, sceRtcGetMonth, sceRtcGetDay, sceRtcGetHour, sceRtcGetMinute, sceRtcGetSecond, sceRtcGetMicrosecond, sceRtcSetYear, sceRtcSetMonth, sceRtcSetDay, sceRtcSetHour, sceRtcSetMinute, sceRtcSetSecond, sceRtcSetMicrosecond](../../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - inferred component behavior without confirmed hardware trace. Component setters validate individual boundaries (e.g. day 1..31) independently without cross-field calendar validation; getters return `0x80B50002` (`SCE_RTC_ERROR_INVALID_POINTER`) for a null pointer
|
||||
|
||||
### Functional
|
||||
|
||||
Reference in new issue
Block a user