From b7d02133f132c1fd7e315eaba8b53ec83b4c35da Mon Sep 17 00:00:00 2001 From: b3t33 <> Date: Tue, 19 Jan 2021 22:58:32 +0100 Subject: [PATCH] Fix possible panic in NaiveDate::from_num_days_from_ce_opt Add some test including panic triggering example `NaiveDate::from_num_days_from_ce_opt(i32::MAX)`. As the function already yields `None` for `i32::Max - 365`, this fix does not change the behaviour, while preventing a panic. --- CHANGELOG.md | 1 + src/naive/date.rs | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16a9063b60..29cf0c0a1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Versions with only mechanical changes will be omitted from the following list. * Add support for microseconds timestamps serde serialization/deserialization (#304) * Fix `DurationRound` is not TZ aware (#495) * Implement `DurationRound` for `NaiveDateTime` +* Fix `NaiveDate::from_num_days_from_ce_opt` panic on overflow ## 0.4.19 diff --git a/src/naive/date.rs b/src/naive/date.rs index 989254ae5f..a9a5d341e6 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -415,11 +415,13 @@ impl NaiveDate { /// assert_eq!(from_ndays_opt(-100_000_000), None); /// ``` pub fn from_num_days_from_ce_opt(days: i32) -> Option { - let days = days + 365; // make December 31, 1 BCE equal to day 0 - let (year_div_400, cycle) = div_mod_floor(days, 146_097); - let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); - let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); - NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)) + // make December 31, 1 BCE equal to day 0 + days.checked_add(365).and_then(|days| { + let (year_div_400, cycle) = div_mod_floor(days, 146_097); + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, Of::new(ordinal, flags)) + }) } /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week @@ -2027,6 +2029,14 @@ mod tests { } } + #[test] + fn test_date_from_num_days_from_ce_opt() { + let ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days); + ndays_from_ce(i32::MAX); + assert!(ndays_from_ce(0).is_some()); + ndays_from_ce(i32::MIN); + } + #[test] fn test_date_from_num_days_from_ce() { let from_ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days);