mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK: Avoid overflow in Duration::to_time_units() with fraction near 1
With numerators or denominators approaching NumericLimits<u32>::max(), we could overflow in the sum of the remainder and the rounding contribution. Instead, divide them separately and sum them afterward.
This commit is contained in:
committed by
Gregory Bertilson
parent
affbe61da0
commit
3844edaaed
Notes:
github-actions[bot]
2026-04-16 20:09:36 +00:00
Author: https://github.com/Zaggy1024 Commit: https://github.com/LadybirdBrowser/ladybird/commit/3844edaaedc Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8936
14
AK/Time.cpp
14
AK/Time.cpp
@@ -231,11 +231,17 @@ i64 Duration::to_time_units(u32 numerator, u32 denominator) const
|
|||||||
|
|
||||||
auto seconds_product = saturating_mul(m_seconds, static_cast<i64>(denominator));
|
auto seconds_product = saturating_mul(m_seconds, static_cast<i64>(denominator));
|
||||||
auto time_units = seconds_product / numerator;
|
auto time_units = seconds_product / numerator;
|
||||||
auto remainder = seconds_product % numerator;
|
auto seconds_remainder_dividend = seconds_product % numerator;
|
||||||
|
|
||||||
auto remainder_in_nanoseconds = remainder * 1'000'000'000;
|
auto seconds_remainder_nanosecond_dividend = seconds_remainder_dividend * 1'000'000'000;
|
||||||
auto rounding_half = static_cast<i64>(numerator) * 500'000'000;
|
auto rounding_half_nanosecond_dividend = static_cast<i64>(numerator) * 500'000'000;
|
||||||
time_units = saturating_add(time_units, ((static_cast<i64>(m_nanoseconds) * denominator + remainder_in_nanoseconds + rounding_half) / numerator) / 1'000'000'000);
|
auto sub_seconds_nanosecond_dividend = (static_cast<i64>(m_nanoseconds) * denominator) + seconds_remainder_nanosecond_dividend;
|
||||||
|
|
||||||
|
auto sub_seconds_nanosecond_units = sub_seconds_nanosecond_dividend / numerator;
|
||||||
|
auto sub_seconds_units_remainder_nanosecond_dividend = sub_seconds_nanosecond_dividend % numerator;
|
||||||
|
auto rounding_adjustment_nanosecond_units = (rounding_half_nanosecond_dividend + sub_seconds_units_remainder_nanosecond_dividend) / numerator;
|
||||||
|
|
||||||
|
time_units = saturating_add(time_units, (sub_seconds_nanosecond_units + rounding_adjustment_nanosecond_units) / 1'000'000'000);
|
||||||
|
|
||||||
return time_units;
|
return time_units;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -986,6 +986,8 @@ TEST_CASE(time_units)
|
|||||||
EXPECT_EQ(Duration::from_seconds(2'147'483'649).to_time_units(1, NumericLimits<u32>::max()), NumericLimits<i64>::max());
|
EXPECT_EQ(Duration::from_seconds(2'147'483'649).to_time_units(1, NumericLimits<u32>::max()), NumericLimits<i64>::max());
|
||||||
EXPECT_EQ(Duration::from_seconds(2'147'483'648).to_time_units(1, NumericLimits<u32>::max()), NumericLimits<i64>::max() - (NumericLimits<u32>::max() / 2));
|
EXPECT_EQ(Duration::from_seconds(2'147'483'648).to_time_units(1, NumericLimits<u32>::max()), NumericLimits<i64>::max() - (NumericLimits<u32>::max() / 2));
|
||||||
|
|
||||||
|
EXPECT_EQ((Duration::from_seconds(1) + Duration::from_nanoseconds(999'999'999)).to_time_units(NumericLimits<u32>::max(), NumericLimits<u32>::max() - 1), 2);
|
||||||
|
|
||||||
EXPECT_DEATH("From time units with zero numerator", (void)Duration::from_time_units(1, 0, 1));
|
EXPECT_DEATH("From time units with zero numerator", (void)Duration::from_time_units(1, 0, 1));
|
||||||
EXPECT_DEATH("From time units with zero denominator", (void)Duration::from_time_units(1, 1, 0));
|
EXPECT_DEATH("From time units with zero denominator", (void)Duration::from_time_units(1, 1, 0));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user