AK: Handle integer negative seconds in Duration::from_time_units()

When passed values that result in a negative integer number of seconds,
we would end up with a nanoseconds component that was outside the
allowed range in Duration. When we get an exact second of nanoseconds,
we can just increment the seconds and reset the nanoseconds to correct
this.

Fixes a crash on https://athenacrisis.com/#athena-crisis.
This commit is contained in:
Zaggy1024 2026-01-23 12:36:28 -06:00 committed by Alexander Kalenik
parent 0f18e6e348
commit 9ce018cd0c
2 changed files with 6 additions and 0 deletions

View file

@ -84,6 +84,10 @@ Duration Duration::from_time_units(i64 time_units, u32 numerator, u32 denominato
auto seconds_in_time_units = seconds * denominator / numerator;
auto remainder_in_time_units = time_units - seconds_in_time_units;
auto nanoseconds = ((remainder_in_time_units * 1'000'000'000 * numerator) + (denominator / 2)) / denominator;
if (nanoseconds == 1'000'000'000) {
seconds++;
nanoseconds = 0;
}
VERIFY(nanoseconds >= 0);
VERIFY(nanoseconds < 1'000'000'000);
return Duration(seconds, static_cast<u32>(nanoseconds));

View file

@ -959,6 +959,8 @@ TEST_CASE(time_units)
EXPECT_EQ(Duration::from_time_units((NumericLimits<i64>::min() / 2), 2, 1), Duration::from_seconds(NumericLimits<i64>::min()));
EXPECT_EQ(Duration::from_time_units((NumericLimits<i64>::min() / 2) - 1, 2, 1), Duration::from_seconds(NumericLimits<i64>::min()));
EXPECT_EQ(Duration::from_time_units(-43776, 1, 14592), Duration::from_seconds(-3));
EXPECT_EQ(Duration::from_milliseconds(999).to_time_units(1, 48'000), 47'952);
EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500);
EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500);