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(prost-types): Fix date-time parsing #1096

Merged
merged 2 commits into from
Jul 12, 2024

Conversation

mumbleskates
Copy link
Contributor

Two bugs revealed so far from fuzz testing in bilrost:

  • parse_two_digit_numeric does not check the length of its input before calling split_at, potentially causing a panic
  • a logic error in the translation of year_to_seconds from the original musl implementation caused it to treat the year 1900 as a leap year, causing (i believe) every date from 1900-01-01 to 1900-03-01 to be offset one day into the past when converting from DateTime to Timestamp.

@mumbleskates
Copy link
Contributor Author

Here's another suggested fix for some weirdness that fuzzing failures highlighted: mumbleskates/bilrost@2e43e02

Copy link
Collaborator

@caspermeijn caspermeijn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution

// Fast path for years 1900 - 2038.
if year as u64 <= 138 {
// Fast path for years 1901 - 2038.
if (1..=138).contains(&year) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So basically, you are saying that the fast path was incorrect for 1900, but the slow path is correct. I can't reason why that is, but I assume that you are right :-)

Copy link
Contributor Author

@mumbleskates mumbleskates Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cited function in musl actually writes this condition as if (year-2ULL <= 136) {... which isn't the same thing as if year as u64 <= 138 { at all! if year is either 0 or 1 in the original function it wraps to max.

the musl code's fast-path works within i32 seconds of the epoch, which ranges from 1901-12-13 to 2038-01-18, so it actually skips the fast-path for 1901 as well because the start of that year is an underflow. for our code, we are calculating in i64 and returning an i128 anyway so it doesn't matter. (the code in this pr is still equally correct here if we write if (1..=199).contains(&year) { :) )

what DOES matter is that the fast-path ignores the century rule for leap years, because 2000 is a multiple of 400 and happens to be one! it's also the only century that occurs in the i32 epoch range. so the fast-path logic is actually WRONG when applied to any year outside 1901..=2099, even without integer wrapping.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand how this could happen. That is a subtle, but important difference. Thanks for the extensive explanation!

@caspermeijn caspermeijn changed the title upstream date-time parsing fixes fix(prost-types): Fix date-time parsing Jul 12, 2024
@caspermeijn caspermeijn added this pull request to the merge queue Jul 12, 2024
@caspermeijn
Copy link
Collaborator

Here's another suggested fix for some weirdness that fuzzing failures highlighted: mumbleskates/bilrost@2e43e02

Could you create a PR for that? Thanks.

Merged via the queue into tokio-rs:master with commit 6481c61 Jul 12, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants