Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(datetime): Verify leap years #631

Merged
merged 3 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions crates/toml/tests/decoder_compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@ fn main() {
let decoder = decoder::Decoder;
let mut harness = toml_test_harness::DecoderHarness::new(decoder);
harness.version("1.0.0");
harness
.ignore([
"invalid/datetime/feb-30.toml",
"invalid/datetime/feb-29.toml",
"invalid/local-date/feb-30.toml",
"invalid/local-date/feb-29.toml",
"invalid/local-datetime/feb-29.toml",
"invalid/local-datetime/feb-30.toml",
])
.unwrap();
harness.ignore([]).unwrap();
harness.test();
}

Expand Down
13 changes: 11 additions & 2 deletions crates/toml_datetime/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,15 @@ impl FromStr for Datetime {
if date.month < 1 || date.month > 12 {
return Err(DatetimeParseError {});
}
if date.day < 1 || date.day > 31 {
let is_leap_year =
(date.year % 4 == 0) && ((date.year % 100 != 0) || (date.year % 400 == 0));
let max_days_in_month = match date.month {
2 if is_leap_year => 29,
2 => 28,
4 | 6 | 9 | 11 => 30,
_ => 31,
};
if date.day < 1 || date.day > max_days_in_month {
return Err(DatetimeParseError {});
}

Expand Down Expand Up @@ -381,7 +389,8 @@ impl FromStr for Datetime {
if time.minute > 59 {
return Err(DatetimeParseError {});
}
if time.second > 59 {
// 00-58, 00-59, 00-60 based on leap second rules
if time.second > 60 {
return Err(DatetimeParseError {});
}
if time.nanosecond > 999_999_999 {
Expand Down
36 changes: 30 additions & 6 deletions crates/toml_edit/src/parser/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use winnow::combinator::alt;
use winnow::combinator::cut_err;
use winnow::combinator::opt;
use winnow::combinator::preceded;
use winnow::stream::Stream as _;
use winnow::token::one_of;
use winnow::token::take_while;
use winnow::trace::trace;
Expand Down Expand Up @@ -53,12 +54,35 @@ pub(crate) fn date_time(input: &mut Input<'_>) -> PResult<Datetime> {

// full-date = date-fullyear "-" date-month "-" date-mday
pub(crate) fn full_date(input: &mut Input<'_>) -> PResult<Date> {
trace(
"full-date",
(date_fullyear, b'-', cut_err((date_month, b'-', date_mday)))
.map(|(year, _, (month, _, day))| Date { year, month, day }),
)
.parse_next(input)
trace("full-date", full_date_).parse_next(input)
}

fn full_date_(input: &mut Input<'_>) -> PResult<Date> {
let year = date_fullyear.parse_next(input)?;
let _ = b'-'.parse_next(input)?;
let month = cut_err(date_month).parse_next(input)?;
let _ = cut_err(b'-').parse_next(input)?;
let day_start = input.checkpoint();
let day = cut_err(date_mday).parse_next(input)?;

let is_leap_year = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
let max_days_in_month = match month {
2 if is_leap_year => 29,
2 => 28,
4 | 6 | 9 | 11 => 30,
_ => 31,
};
if max_days_in_month < day {
input.reset(day_start);
return Err(winnow::error::ErrMode::from_external_error(
input,
winnow::error::ErrorKind::Verify,
CustomError::OutOfRange,
)
.cut());
}

Ok(Date { year, month, day })
}

// partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
Expand Down
11 changes: 1 addition & 10 deletions crates/toml_edit/tests/decoder_compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ fn main() {
let decoder = decoder::Decoder;
let mut harness = toml_test_harness::DecoderHarness::new(decoder);
harness.version("1.0.0");
harness
.ignore([
"invalid/datetime/feb-30.toml",
"invalid/datetime/feb-29.toml",
"invalid/local-date/feb-30.toml",
"invalid/local-date/feb-29.toml",
"invalid/local-datetime/feb-29.toml",
"invalid/local-datetime/feb-30.toml",
])
.unwrap();
harness.ignore([]).unwrap();
harness.test();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 29
|
1 | "not a leap year" = 2100-02-29T15:15:15Z
| ^
invalid date-time
value is out of range
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 44
|
1 | "only 28 or 29 days in february" = 1988-02-30T15:15:15Z
| ^
invalid date-time
value is out of range
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 29
|
1 | "not a leap year" = 2100-02-29
| ^
invalid date-time
value is out of range
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 44
|
1 | "only 28 or 29 days in february" = 1988-02-30
| ^
invalid date-time
value is out of range
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 29
|
1 | "not a leap year" = 2100-02-29T15:15:15
| ^
invalid date-time
value is out of range
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TOML parse error at line 1, column 44
|
1 | "only 28 or 29 days in february" = 1988-02-30T15:15:15
| ^
invalid date-time
value is out of range
2 changes: 1 addition & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ unknown-git = "deny"
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
allow-git = ["https://github.com/rust-fuzz/libfuzzer-sys"]

[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
Expand Down
Loading