From 006fc6f7975b3a6b64329847b780622aab392109 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 28 Nov 2022 13:14:06 -0500 Subject: [PATCH] Update use of libc::timespec to prepare for future libc version In a future release of the `libc` crate, `libc::timespec` will contain private padding fields on `*-linux-musl` targets and so the struct will no longer be able to be created using the literal initialization syntax. Update places where `libc::timespec` is created to first zero initialize the value and then update the `tv_sec` and `tv_nsec` fields manually. Many of these places are in `const fn`s so a helper function `zero_init_timespec()` is introduced to help with this as `std::mem::MaybeUninit::zeroed()` is not a `const` function. Some matches on `libc::timespec` are also updated to include a trailing `..` pattern which works when `libc::timespec` has additional, private fields as well as when it does not (like for `x86_64-unknown-linux-gnu`). --- src/sys/time.rs | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/sys/time.rs b/src/sys/time.rs index a724084950..0042c45084 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -6,6 +6,13 @@ use std::convert::From; use std::time::Duration; use std::{cmp, fmt, ops}; +const fn zero_init_timespec() -> timespec { + // `std::mem::MaybeUninit::zeroed()` is not yet a const fn + // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of + // the appropriate size to zero and then transmute it to a timespec value. + unsafe { std::mem::transmute([0u8; std::mem::size_of::()]) } +} + #[cfg(any( all(feature = "time", any(target_os = "android", target_os = "linux")), all( @@ -20,7 +27,7 @@ use std::{cmp, fmt, ops}; ) ))] pub(crate) mod timer { - use crate::sys::time::TimeSpec; + use crate::sys::time::{zero_init_timespec, TimeSpec}; use bitflags::bitflags; #[derive(Debug, Clone, Copy)] @@ -29,14 +36,8 @@ pub(crate) mod timer { impl TimerSpec { pub const fn none() -> Self { Self(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, - it_value: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, + it_interval: zero_init_timespec(), + it_value: zero_init_timespec(), }) } } @@ -57,10 +58,7 @@ pub(crate) mod timer { fn from(expiration: Expiration) -> TimerSpec { match expiration { Expiration::OneShot(t) => TimerSpec(libc::itimerspec { - it_interval: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }, + it_interval: zero_init_timespec(), it_value: *t.as_ref(), }), Expiration::IntervalDelayed(start, interval) => { @@ -118,6 +116,7 @@ pub(crate) mod timer { libc::timespec { tv_sec: 0, tv_nsec: 0, + .. }, it_value: ts, }) => Expiration::OneShot(ts.into()), @@ -257,18 +256,17 @@ impl PartialOrd for TimeSpec { impl TimeValLike for TimeSpec { #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 fn seconds(seconds: i64) -> TimeSpec { assert!( (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), "TimeSpec out of bounds; seconds={}", seconds ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: seconds as time_t, - tv_nsec: 0, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds as time_t; + TimeSpec(ts) } #[inline] @@ -292,18 +290,18 @@ impl TimeValLike for TimeSpec { /// Makes a new `TimeSpec` with given number of nanoseconds. #[inline] + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 fn nanoseconds(nanoseconds: i64) -> TimeSpec { let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); assert!( (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), "TimeSpec out of bounds" ); - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: secs as time_t, - tv_nsec: nanos as timespec_tv_nsec_t, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = secs as time_t; + ts.tv_nsec = nanos as timespec_tv_nsec_t; + TimeSpec(ts) } // The cast is not unnecessary on all platforms. @@ -337,10 +335,10 @@ impl TimeSpec { /// Construct a new `TimeSpec` from its components #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { - Self(timespec { - tv_sec: seconds, - tv_nsec: nanoseconds, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + Self(ts) } fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { @@ -360,13 +358,13 @@ impl TimeSpec { self.0.tv_nsec } + #[cfg_attr(target_env = "musl", allow(deprecated))] + // https://github.com/rust-lang/libc/issues/1848 pub const fn from_duration(duration: Duration) -> Self { - #[cfg_attr(target_env = "musl", allow(deprecated))] - // https://github.com/rust-lang/libc/issues/1848 - TimeSpec(timespec { - tv_sec: duration.as_secs() as time_t, - tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t, - }) + let mut ts = zero_init_timespec(); + ts.tv_sec = duration.as_secs() as time_t; + ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; + TimeSpec(ts) } pub const fn from_timespec(timespec: timespec) -> Self {