Skip to content

Commit

Permalink
Defer to num_threads for OS support
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Dec 23, 2021
1 parent f6baa3f commit bf5f830
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 42 deletions.
24 changes: 3 additions & 21 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ jobs:
matrix:
rust: ["1.53", stable]
os:
- { name: Ubuntu, value: ubuntu-20.04, has_local_offset: true }
- { name: Windows, value: windows-latest, has_local_offset: true }
- { name: MacOS, value: macOS-latest, has_local_offset: false }
- { name: Ubuntu, value: ubuntu-20.04 }
- { name: Windows, value: windows-latest }
- { name: MacOS, value: macOS-latest }

steps:
- name: Checkout sources
Expand Down Expand Up @@ -203,24 +203,6 @@ jobs:
--features macros
if: matrix.os.has_local_offset == true

# Due to the soundness bug on Unix-like platforms, adding the local-offset flag doesn't
# actually add any new behavior. Since we know nothing changes, we can unconditionally enable
# the flag.
- name: Check feature powerset
uses: actions-rs/cargo@v1
with:
command: hack
args: |
check
--feature-powerset
--optional-deps
--group-features serde,rand
--group-features formatting,parsing
--group-features serde-human-readable,serde-well-known
--exclude-features default,quickcheck-dep,time-macros,itoa
--features macros,local-offset
if: matrix.os.has_local_offset == false

- name: Test
uses: actions-rs/cargo@v1
with:
Expand Down
6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,9 @@ rand = { version = "0.8.4", optional = true, default-features = false }
serde = { version = "1.0.126", optional = true, default-features = false }
time-macros = { version = "=0.2.3", path = "time-macros", optional = true }

[target.'cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))'.dependencies]
[target.'cfg(target_family = "unix")'.dependencies]
libc = "0.2.98"

[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies]
num_threads = "0.1.0"
num_threads = "0.1.2"

[dev-dependencies]
rand = { version = "0.8.4", default-features = false }
Expand Down
28 changes: 11 additions & 17 deletions src/sys/local_offset_at/unix.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
//! Get the system's UTC offset on Unix.
#[cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))]

use core::convert::TryInto;
#[cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))]
use core::mem::MaybeUninit;

use crate::{OffsetDateTime, UtcOffset};

/// Obtain the system's UTC offset.
// This fallback is used whenever an operating system doesn't have a method below for determine if a
// process is single threaded.
#[cfg(not(any(target_os = "linux", target_os = "freebsd", unsound_local_offset)))]
#[allow(clippy::missing_const_for_fn)]
pub(super) fn local_offset_at(_datetime: OffsetDateTime) -> Option<UtcOffset> {
None
}

/// Convert the given Unix timestamp to a `libc::tm`. Returns `None` on any error.
///
/// # Safety
Expand All @@ -24,7 +14,6 @@ pub(super) fn local_offset_at(_datetime: OffsetDateTime) -> Option<UtcOffset> {
/// This method will remain `unsafe` until `std::env::set_var` is deprecated or has its behavior
/// altered. This method is, on its own, safe. It is the presence of a safe, unsound way to set
/// environment variables that makes it unsafe.
#[cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))]
unsafe fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
extern "C" {
#[cfg_attr(target_os = "netbsd", link_name = "__tzset50")]
Expand Down Expand Up @@ -56,8 +45,10 @@ unsafe fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {

/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
// `tm_gmtoff` extension
#[cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))]
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
#[cfg(not(all(
unsound_local_offset,
any(target_os = "solaris", target_os = "illumos")
)))]
fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
let seconds: i32 = tm.tm_gmtoff.try_into().ok()?;
UtcOffset::from_hms(
Expand All @@ -69,8 +60,10 @@ fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
}

/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
#[cfg(unsound_local_offset)]
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
#[cfg(all(
unsound_local_offset,
any(target_os = "solaris", target_os = "illumos")
))]
fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
use core::convert::TryFrom;

Expand Down Expand Up @@ -107,12 +100,13 @@ fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
}

/// Obtain the system's UTC offset.
#[cfg(any(target_os = "linux", target_os = "freebsd", unsound_local_offset))]
pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
// Ensure that the process is single-threaded unless the user has explicitly opted out of this
// check. This is to prevent issues with the environment being mutated by a different thread in
// the process while execution of this function is taking place, which can cause a segmentation
// fault by dereferencing a dangling pointer.
// If the `num_threads` crate is incapable of determining the number of running threads, then
// we conservatively return `None` to avoid a soundness bug.
if !cfg!(unsound_local_offset) && num_threads::is_single_threaded() != Some(true) {
return None;
}
Expand Down

0 comments on commit bf5f830

Please sign in to comment.