Skip to content

Commit

Permalink
Changelog: add history of relation between chrono and time 0.1
Browse files Browse the repository at this point in the history
(for next release)
  • Loading branch information
pitdicker committed Sep 4, 2023
1 parent 59cc2a8 commit 8e19c02
Showing 1 changed file with 85 additions and 0 deletions.
85 changes: 85 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,91 @@ Changelog

This file will be updated on new releases, there usually won't be an `Unreleased` section.

## Unreleased

### Relation between chrono and time 0.1

Since Rust 0.7 the standard library had a `time` module. It moved to `libextra`, and then to a
`libtime` library shipped alongside the standard library. In 2014 the work on chrono started in
order to provide a full-featured date and time library in Rust. Some improvements from chrono made
it into the standard library, notably the `chrono::Duration` type was moved to
`std::time::Duration` ([rust#15934]).

In preparation of Rust 1.0 at the end of 2014 `libtime` was moved out of the Rust distro and into
the `time` crate to eventually be redesigned ([rust#18832], [rust#18858]), just like the `num` and
`rand` crates. Naturally chrono gained `time` as a dependency. `time` also started re-exporting
`std::time::Duration`. Later the standard library was changed to have a more limited unsigned
`Duration` type ([rust#24920], [RFC 1040]), while the `time` crate kept the full functionality with
`time::Duration`. And `time::Duration` was part of the public API of chrono.

By 2016 `time` 0.1 lived under the `rust-lang-deprecated` organisation and was not actively
maintained ([time#136]). Chrono absorbed the platform functionality and `Duration` type of the time
crate in [chrono#478] (the work started in [chrono#286]). But because of the `time::Duration` type
and to not make this a breaking change `time` would still remain as a dependency. Crates could opt
to use chrono without the `old-time` feature to drop the dependency. During this time @jhpratt would
take over `time` and release what amounts to a new crate under time 0.2.

[rust#15934]: https://github.com/rust-lang/rust/pull/15934
[rust#18832]: https://github.com/rust-lang/rust/pull/18832#issuecomment-62448221
[rust#18858]: https://github.com/rust-lang/rust/pull/18858
[rust#24920]: https://github.com/rust-lang/rust/pull/24920
[RFC 1040]: https://rust-lang.github.io/rfcs/1040-duration-reform.html
[time#136]: https://github.com/time-rs/time/issues/136
[chrono#286]: https://github.com/chronotope/chrono/pull/286
[chrono#478]: https://github.com/chronotope/chrono/pull/478

#### Security advisories

In november 2020 [CVE-2020-26235] and [RUSTSEC-2020-0071] were opened against the time crate, and
the start of quite some frustration for the rust ecosystem. @quininer found that calls to
`localtime_r` may be unsound ([chrono#499]). Eventually, almost a year later, this was also made
into a security advisory against chrono as [RUSTSEC-2020-0159], which had platform code similar to
`time`.

The issue: on Unix-like systems a process is given a time zone id or description via the `TZ`
environment variable. We need this time zone data to calculate the current local time from a value
that is in UTC, such as the time from the system clock. `time` 0.1 and chrono used the POSIX
function `localtime_r` to do the conversion to local time, which reads the `TZ` variable.

Rust assumes the environment to be writable and uses locks to access it from multiple threads. So do
some other programming languages and libraries, but there is no shared locking mechanism. More
importantly POSIX declares modifying the environment in a multi-threaded process as unsafe, and
`getenv` in libc can't be changed to just take a lock because it returns a pointer to the data (see
[rust#27970] for more discussion).

Solving this situation will take the combined effort of the various libc's, standard libraries, and
the code using them. Or the `TZ` variable should just not be modified in a multi-threaded process.

Since [chrono#677], released as version 4.20, chrono no longer uses `localtime_r` but provides a
pure-rust solution. This makes changes of the `TZ` variable from Rust code sound. The fix involves
reading the `TZ` variable and/or the `/etc/localtime` symlink, caching, implementing the logic for
POSIX TZ String time zone transitions, and parsing TZif files and working with that data. The code
mostly comes from the work by @x-hgg-x on the [tz-rs crate].

The good thing to come from this is that we can improve beyond what the platform offers.

[CVE-2020-26235]: https://nvd.nist.gov/vuln/detail/CVE-2020-26235
[RUSTSEC-2020-0071]: https://rustsec.org/advisories/RUSTSEC-2020-0071
[chrono#499]: https://github.com/chronotope/chrono/pull/499
[RUSTSEC-2020-0159]: https://rustsec.org/advisories/RUSTSEC-2020-0159.html
[rust#27970]: https://github.com/rust-lang/rust/issues/27970
[chrono#677]: https://github.com/chronotope/chrono/pull/677
[tz-rs crate]: https://crates.io/crates/tz-rs

#### Removing time 0.1

Still users of chrono would get a security advisory because of the time 0.1 dependency, which was
never fixed. We were careful not to break backwards compatibility with the `time::Duration` type.
But how many crates actually depend on this compatibility with time 0.1? Remember it was
unmaintained for multiple years, and now had much improved new releases. After a primitive
crater-like run it turned out only a tiny number of crates would break ([chrono#1095]), which we
reached out to if still maintained.

With 0.4.29 chrono finally drops the time 0.1 dependency, making an end to the *many* security
advisory warnings against crates depending on chrono.

[chrono#1095]: https://github.com/chronotope/chrono/pull/1095

## [0.4.28] - 2023-08-30

This release fixes a test failure on 32-bit targets introduced with 0.4.27,
Expand Down

0 comments on commit 8e19c02

Please sign in to comment.