diff --git a/crates/toml/tests/decoder_compliance.rs b/crates/toml/tests/decoder_compliance.rs index a4ebbe58..58288837 100644 --- a/crates/toml/tests/decoder_compliance.rs +++ b/crates/toml/tests/decoder_compliance.rs @@ -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(); } diff --git a/crates/toml_datetime/src/datetime.rs b/crates/toml_datetime/src/datetime.rs index 871522df..1b37c700 100644 --- a/crates/toml_datetime/src/datetime.rs +++ b/crates/toml_datetime/src/datetime.rs @@ -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 {}); } @@ -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 { diff --git a/crates/toml_edit/src/parser/datetime.rs b/crates/toml_edit/src/parser/datetime.rs index 6e89b977..96a3854d 100644 --- a/crates/toml_edit/src/parser/datetime.rs +++ b/crates/toml_edit/src/parser/datetime.rs @@ -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; @@ -53,12 +54,35 @@ pub(crate) fn date_time(input: &mut Input<'_>) -> PResult { // full-date = date-fullyear "-" date-month "-" date-mday pub(crate) fn full_date(input: &mut Input<'_>) -> PResult { - 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 { + 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] diff --git a/crates/toml_edit/tests/decoder_compliance.rs b/crates/toml_edit/tests/decoder_compliance.rs index 357cfd51..37a9335e 100644 --- a/crates/toml_edit/tests/decoder_compliance.rs +++ b/crates/toml_edit/tests/decoder_compliance.rs @@ -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(); } diff --git a/crates/toml_edit/tests/fixtures/invalid/datetime/feb-29.stderr b/crates/toml_edit/tests/fixtures/invalid/datetime/feb-29.stderr index e69de29b..63fac67c 100644 --- a/crates/toml_edit/tests/fixtures/invalid/datetime/feb-29.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/datetime/feb-29.stderr @@ -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 diff --git a/crates/toml_edit/tests/fixtures/invalid/datetime/feb-30.stderr b/crates/toml_edit/tests/fixtures/invalid/datetime/feb-30.stderr index e69de29b..2b5212af 100644 --- a/crates/toml_edit/tests/fixtures/invalid/datetime/feb-30.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/datetime/feb-30.stderr @@ -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 diff --git a/crates/toml_edit/tests/fixtures/invalid/local-date/feb-29.stderr b/crates/toml_edit/tests/fixtures/invalid/local-date/feb-29.stderr index e69de29b..b0ae76dd 100644 --- a/crates/toml_edit/tests/fixtures/invalid/local-date/feb-29.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/local-date/feb-29.stderr @@ -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 diff --git a/crates/toml_edit/tests/fixtures/invalid/local-date/feb-30.stderr b/crates/toml_edit/tests/fixtures/invalid/local-date/feb-30.stderr index e69de29b..7f643481 100644 --- a/crates/toml_edit/tests/fixtures/invalid/local-date/feb-30.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/local-date/feb-30.stderr @@ -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 diff --git a/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-29.stderr b/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-29.stderr index e69de29b..8aac7125 100644 --- a/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-29.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-29.stderr @@ -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 diff --git a/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-30.stderr b/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-30.stderr index e69de29b..6175c5e8 100644 --- a/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-30.stderr +++ b/crates/toml_edit/tests/fixtures/invalid/local-datetime/feb-30.stderr @@ -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 diff --git a/deny.toml b/deny.toml index 21fa937f..e473ea74 100644 --- a/deny.toml +++ b/deny.toml @@ -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