Skip to content

Commit

Permalink
Rewrite history sections for clarity and consistency
Browse files Browse the repository at this point in the history
  • Loading branch information
djc authored and pitdicker committed Sep 7, 2023
1 parent 7387fe7 commit eee59e3
Showing 1 changed file with 48 additions and 50 deletions.
98 changes: 48 additions & 50 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,27 +378,28 @@
//!
//! ## 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]).
//! Rust first had a `time` module added to `std` in its 0.7 release. It later moved to
//! `libextra`, and then to a `libtime` library shipped alongside the standard library. In 2014
//! 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, `chrono::Duration`
//! was included as `std::time::Duration` ([rust#15934]) in 2014.
//!
//! 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.
//! into the `time` crate to eventually be redesigned ([rust#18832], [rust#18858]), like the
//! `num` and `rand` crates. Of course chrono kept its dependency on this `time` crate. `time`
//! started re-exporting `std::time::Duration` during this period. 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`. `time::Duration` had been a
//! part of chrono's public API.
//!
//! 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.
//! maintained ([time#136]). chrono absorbed the platform functionality and `Duration` type of the
//! `time` crate in [chrono#478] (the work started in [chrono#286]). In order to preserve
//! compatibility with downstream crates depending on `time` and `chrono` sharing a `Duration`
//! type, chrono kept depending on time 0.1. chrono offered the option to opt out of the `time`
//! dependency by disabling the `oldtime` feature (swapping it out for an effectively similar
//! chrono type). In 2019, @jhpratt took over maintenance on the `time` crate and released what
//! amounts to a new crate as `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
Expand All @@ -409,35 +410,29 @@
//! [chrono#286]: https://github.com/chronotope/chrono/pull/286
//! [chrono#478]: https://github.com/chronotope/chrono/pull/478
//!
//! #### Security advisories
//! ## 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`.
//! In November of 2020 [CVE-2020-26235] and [RUSTSEC-2020-0071] were opened against the `time` crate.
//! @quininer had 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.
//! On Unix-like systems a process is given a timezone id or description via the `TZ` environment
//! variable. We need this timezone 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).
//! Some other programming languages and libraries use similar locking strategies, but these are
//! typically not shared across languages. More importantly, POSIX declares modifying the
//! environment in a multi-threaded process as unsafe, and `getenv` in libc can't be changed to
//! take a lock because it returns a pointer to the data (see [rust#27970] for more discussion).
//!
//! Since version 4.20 chrono no longer uses `localtime_r` but uses rust code to query the time zone
//! (from the `TZ` variable or via `iana-time-zone` as a fallback) and work with data from the
//! system time zone database directly. This involves the logic for POSIX TZ Strings, and parsing
//! TZif files and working with their transition tables. The code mostly comes from the work by
//! @x-hgg-x on the [tz-rs crate].
//!
//! So when reading the `TZ` environment variable chrono now respects the Rust locks. However in
//! general it is probably best to avoid modifying the environment.
//!
//! The good thing to come from this is that we can improve beyond what the platform offers.
//! Since version 4.20 chrono no longer uses `localtime_r`, instead using Rust code to query the
//! timezone (from the `TZ` variable or via `iana-time-zone` as a fallback) and work with data
//! from the system timezone database directly. The code for this was forked from the [tz-rs crate]
//! by @x-hgg-x. As such, chrono now respects the Rust lock when reading the `TZ` environment
//! variable. In general, code should avoid modifying the environment.
//!
//! [CVE-2020-26235]: https://nvd.nist.gov/vuln/detail/CVE-2020-26235
//! [RUSTSEC-2020-0071]: https://rustsec.org/advisories/RUSTSEC-2020-0071
Expand All @@ -447,17 +442,20 @@
//! [chrono#677]: https://github.com/chronotope/chrono/pull/677
//! [tz-rs crate]: https://crates.io/crates/tz-rs
//!
//! #### Removing time 0.1
//! ## 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.
//! Because time 0.1 has been unmaintained for years, however, the security advisory mentioned
//! above has not been addressed. While chrono maintainers were careful not to break backwards
//! compatibility with the `time::Duration` type, there has been a long stream of issues from
//! users inquiring about the time 0.1 dependency with the vulnerability. We investigated the
//! potential breakage of removing the time 0.1 dependency in [chrono#1095] using a crater-like
//! experiment and determined that the potential for breaking (public) dependencies is very low.
//! We reached out to those few crates that did still depend on compatibility with time 0.1.
//!
//! With 0.4.30 chrono finally drops the time 0.1 dependency, making an end to the *many* security
//! advisory warnings against crates depending on chrono.
//! As such, for chrono 0.4.30 we have decided to swap out the time 0.1 `Duration` implementation
//! for a local one that will offer a strict superset of the existing API going forward. This
//! will prevent most downstream users from being affected by the security vulnerability in time
//! 0.1 while minimizing the ecosystem impact of semver-incompatible version churn.
//!
//! [chrono#1095]: https://github.com/chronotope/chrono/pull/1095

Expand Down

0 comments on commit eee59e3

Please sign in to comment.