fix(rtc): reject out-of-range source ticks in date arithmetic

This commit is contained in:
Nicolas Abosch 2026-10-05 00:15:56 -03:00
parent e91eecc402
commit 76b7294f06
2 changed files with 35 additions and 0 deletions

View File

@ -109,6 +109,7 @@ std::int64_t localOffsetSeconds(std::uint64_t utcTick) {
int addTicks(RtcTick* dst, const RtcTick* src, std::int64_t count, std::int64_t unit) {
if (!dst || !src) return SCE_RTC_ERROR_INVALID_POINTER;
if (src->tick > MAX_TICK) return SCE_RTC_ERROR_INVALID_VALUE;
if (count != 0 && (count > std::numeric_limits<std::int64_t>::max() / unit || count < std::numeric_limits<std::int64_t>::min() / unit)) return SCE_RTC_ERROR_INVALID_VALUE;
const std::int64_t delta = count * unit;
if (delta < 0 ? src->tick < static_cast<std::uint64_t>(-(delta + 1)) + 1 : MAX_TICK - src->tick < static_cast<std::uint64_t>(delta)) return SCE_RTC_ERROR_INVALID_VALUE;
@ -118,6 +119,7 @@ int addTicks(RtcTick* dst, const RtcTick* src, std::int64_t count, std::int64_t
int addMonths(RtcTick* dst, const RtcTick* src, std::int64_t months) {
if (!dst || !src) return SCE_RTC_ERROR_INVALID_POINTER;
if (src->tick > MAX_TICK) return SCE_RTC_ERROR_INVALID_VALUE;
RtcDateTime time = fromTick(src->tick);
const std::int64_t monthIndex = time.year * 12 + (time.month - 1) + months;
const std::int64_t year = monthIndex / 12;

View File

@ -4,6 +4,7 @@
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
extern "C" {
int APS5_VABI sceRtcCheckValid(const RtcDateTime*);
@ -168,6 +169,38 @@ int main() {
Require(sceRtcTickAddTicks(&result, &source, 1) == invalidValue);
Require(sceRtcTickAddTicks(nullptr, &source, 1) == invalidPointer);
const std::uint64_t invalidTicks[] = {maxTick + 1, std::numeric_limits<std::uint64_t>::max()};
for (std::uint64_t invalidTick : invalidTicks) {
source.tick = invalidTick;
result.tick = 123;
Require(sceRtcTickAddTicks(&result, &source, 0) == invalidValue && result.tick == 123);
Require(sceRtcTickAddTicks(&result, &source, 1) == invalidValue && result.tick == 123);
Require(sceRtcTickAddTicks(&result, &source, -1) == invalidValue && result.tick == 123);
Require(sceRtcTickAddSeconds(&result, &source, 0) == invalidValue && result.tick == 123);
Require(sceRtcTickAddDays(&result, &source, -1) == invalidValue && result.tick == 123);
Require(sceRtcTickAddMonths(&result, &source, 0) == invalidValue && result.tick == 123);
Require(sceRtcTickAddYears(&result, &source, -1) == invalidValue && result.tick == 123);
Require(sceRtcTickAddTicks(&source, &source, 0) == invalidValue && source.tick == invalidTick);
Require(sceRtcTickAddMonths(&source, &source, -1) == invalidValue && source.tick == invalidTick);
Require(sceRtcTickAddTicks(nullptr, &source, 0) == invalidPointer);
Require(sceRtcTickAddMonths(nullptr, &source, 0) == invalidPointer);
}
source.tick = maxTick;
Require(sceRtcTickAddTicks(&source, &source, 0) == 0 && source.tick == maxTick);
Require(sceRtcTickAddTicks(&source, &source, -1) == 0 && source.tick == maxTick - 1);
source.tick = maxTick;
Require(sceRtcTickAddMonths(&source, &source, 0) == 0 && source.tick == maxTick);
Require(sceRtcTickAddYears(&result, &source, -1) == 0);
Require(sceRtcSetTick(&converted, &result) == 0 && Equal(converted, RtcDateTime{9998, 12, 31, 23, 59, 59, 999999}));
result.tick = 123;
Require(sceRtcTickAddMonths(&result, &source, 1) == invalidValue && result.tick == 123);
Require(sceRtcTickAddTicks(&result, &source, std::numeric_limits<std::int64_t>::min()) == invalidValue && result.tick == 123);
Require(sceRtcTickAddSeconds(&result, &source, std::numeric_limits<std::int64_t>::max()) == invalidValue && result.tick == 123);
source.tick = 0;
Require(sceRtcTickAddMonths(&source, &source, 0) == 0 && source.tick == 0);
Require(sceRtcTickAddMonths(&result, &source, -1) == invalidValue && result.tick == 123);
RtcTick now{};
Require(sceRtcGetCurrentTick(&now) == 0 && now.tick > leapDayTick);
RtcTick local{};