Skip to content

Commit

Permalink
Ensure Secs is 64-bit on sparc and android. (#742)
Browse files Browse the repository at this point in the history
This is needed for y2038 compatibility. Factor out the predicate
for replacing libc::time_t into a `fix_y2038` config, and add
32-bit sparc and android too it.

Also, add a layout testcase for the `Timespec` type.
  • Loading branch information
sunfishcode authored Jul 15, 2023
1 parent 2c99002 commit 1595eea
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 283 deletions.
60 changes: 35 additions & 25 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ fn main() {

// Gather target information.
let arch = var("CARGO_CFG_TARGET_ARCH").unwrap();
let env = var("CARGO_CFG_TARGET_ENV").unwrap();
let inline_asm_name = format!("{}/{}.rs", ASM_PATH, arch);
let inline_asm_name_present = std::fs::metadata(inline_asm_name).is_ok();
let target_os = var("CARGO_CFG_TARGET_OS").unwrap();
let os = var("CARGO_CFG_TARGET_OS").unwrap();
let pointer_width = var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
let endian = var("CARGO_CFG_TARGET_ENDIAN").unwrap();

Expand Down Expand Up @@ -59,15 +60,15 @@ fn main() {
// For now Android uses the libc backend; in theory it could use the
// linux_raw backend, but to do that we'll need to figure out how to
// install the toolchain for it.
if feature_use_libc
let libc = feature_use_libc
|| cfg_use_libc
|| target_os != "linux"
|| os != "linux"
|| !inline_asm_name_present
|| is_unsupported_abi
|| miri
|| ((arch == "powerpc64" || arch == "mips" || arch == "mips64")
&& !rustix_use_experimental_asm)
{
&& !rustix_use_experimental_asm);
if libc {
// Use the libc backend.
use_feature("libc");
} else {
Expand All @@ -86,43 +87,52 @@ fn main() {

// Rust's libc crate groups some OS's together which have similar APIs;
// create similarly-named features to make `cfg` tests more concise.
if target_os == "freebsd" || target_os == "dragonfly" {
let freebsdlike = os == "freebsd" || os == "dragonfly";
if freebsdlike {
use_feature("freebsdlike");
}
if target_os == "openbsd" || target_os == "netbsd" {
let netbsdlike = os == "openbsd" || os == "netbsd";
if netbsdlike {
use_feature("netbsdlike");
}
if target_os == "macos" || target_os == "ios" || target_os == "tvos" || target_os == "watchos" {
let apple = os == "macos" || os == "ios" || os == "tvos" || os == "watchos";
if apple {
use_feature("apple");
}
if target_os == "linux"
|| target_os == "l4re"
|| target_os == "android"
|| target_os == "emscripten"
{
if os == "linux" || os == "l4re" || os == "android" || os == "emscripten" {
use_feature("linux_like");
}
if target_os == "solaris" || target_os == "illumos" {
if os == "solaris" || os == "illumos" {
use_feature("solarish");
}
if target_os == "macos"
|| target_os == "ios"
|| target_os == "tvos"
|| target_os == "watchos"
|| target_os == "freebsd"
|| target_os == "dragonfly"
|| target_os == "openbsd"
|| target_os == "netbsd"
{
if apple || freebsdlike || netbsdlike {
use_feature("bsd");
}

// Add some additional common target combinations.
if target_os == "android" || target_os == "linux" {

// Android and "regular" Linux both use the Linux kernel.
if os == "android" || os == "linux" {
use_feature("linux_kernel");
}

if target_os == "wasi" {
// These platforms have a 32-bit `time_t`.
if libc
&& (arch == "arm"
|| arch == "mips"
|| arch == "sparc"
|| arch == "x86"
|| (arch == "wasm32" && os == "emscripten"))
&& (apple
|| os == "android"
|| os == "emscripten"
|| env == "gnu"
|| (env == "musl" && arch == "x86"))
{
use_feature("fix_y2038");
}

if os == "wasi" {
use_feature_or_nothing("wasi_ext");
}

Expand Down
56 changes: 10 additions & 46 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,11 @@ use crate::fs::{Mode, OFlags, SeekFrom, Stat};
#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
use crate::fs::{StatVfs, StatVfsMountFlags};
use crate::io;
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
use crate::timespec::LibcTimespec;
#[cfg(not(target_os = "wasi"))]
use crate::ugid::{Gid, Uid};
#[cfg(not(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)))]
#[cfg(not(fix_y2038))]
#[cfg(not(target_os = "espidf"))]
use crate::utils::as_ptr;
#[cfg(apple)]
Expand All @@ -83,15 +77,9 @@ use {
core::ptr::null,
};

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
weak!(fn __utimensat64(c::c_int, *const c::c_char, *const LibcTimespec, c::c_int) -> c::c_int);
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
weak!(fn __futimens64(c::c_int, *const LibcTimespec) -> c::c_int);

/// Use a direct syscall (via libc) for `open`.
Expand Down Expand Up @@ -720,10 +708,7 @@ pub(crate) fn utimensat(
) -> io::Result<()> {
// 32-bit gnu version: libc has `utimensat` but it is not y2038 safe by
// default.
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe {
if let Some(libc_utimensat) = __utimensat64.get() {
let libc_times: [LibcTimespec; 2] = [
Expand All @@ -744,13 +729,7 @@ pub(crate) fn utimensat(

// Main version: libc is y2038 safe and has `utimensat`. Or, the platform
// is not y2038 safe and there's nothing practical we can do.
#[cfg(not(any(
apple,
all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)
)))]
#[cfg(not(any(apple, fix_y2038)))]
unsafe {
// Assert that `Timestamps` has the expected layout.
let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
Expand Down Expand Up @@ -879,10 +858,7 @@ pub(crate) fn utimensat(
}
}

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe fn utimensat_old(
dirfd: BorrowedFd<'_>,
path: &CStr,
Expand Down Expand Up @@ -1374,10 +1350,7 @@ fn libc_statvfs_to_statvfs(from: c::statvfs) -> StatVfs {
#[cfg(not(target_os = "espidf"))]
pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
// 32-bit gnu version: libc has `futimens` but it is not y2038 safe by default.
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe {
if let Some(libc_futimens) = __futimens64.get() {
let libc_times: [LibcTimespec; 2] = [
Expand All @@ -1393,13 +1366,7 @@ pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()>

// Main version: libc is y2038 safe and has `futimens`. Or, the platform
// is not y2038 safe and there's nothing practical we can do.
#[cfg(not(any(
apple,
all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)
)))]
#[cfg(not(any(apple, fix_y2038)))]
unsafe {
// Assert that `Timestamps` has the expected layout.
let _ = core::mem::transmute::<Timestamps, [c::timespec; 2]>(times.clone());
Expand Down Expand Up @@ -1445,10 +1412,7 @@ pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()>
}
}

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe fn futimens_old(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> {
let old_times = [
c::timespec {
Expand Down
10 changes: 8 additions & 2 deletions src/backend/libc/fs/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,10 +1087,16 @@ pub type FsWord = u32;
pub type FsWord = u64;

/// `__fsword_t`
// s390x uses `u32` for `statfs` entries, even though `__fsword_t` is `u64`.
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
// s390x uses `u32` for `statfs` entries on glibc, even though `__fsword_t` is
// `u64`.
#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "gnu"))]
pub type FsWord = u32;

/// `__fsword_t`
// s390x uses `u64` for `statfs` entries on musl.
#[cfg(all(target_os = "linux", target_arch = "s390x", target_env = "musl"))]
pub type FsWord = u64;

/// `copyfile_state_t`—State for use with [`fcopyfile`].
///
/// [`fcopyfile`]: crate::fs::fcopyfile
Expand Down
63 changes: 15 additions & 48 deletions src/backend/libc/thread/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use crate::backend::conv::ret;
use crate::io;
#[cfg(not(target_os = "redox"))]
use crate::thread::{NanosleepRelativeResult, Timespec};
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
use crate::timespec::LibcTimespec;
use core::mem::MaybeUninit;
#[cfg(linux_kernel)]
Expand All @@ -30,15 +27,10 @@ use {
)))]
use {crate::thread::ClockId, core::ptr::null_mut};

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
#[cfg(not(target_os = "emscripten"))]
weak!(fn __clock_nanosleep_time64(c::clockid_t, c::c_int, *const LibcTimespec, *mut LibcTimespec) -> c::c_int);
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
weak!(fn __nanosleep64(*const LibcTimespec, *mut LibcTimespec) -> c::c_int);

#[cfg(not(any(
Expand All @@ -58,10 +50,7 @@ pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> Nanos

// 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe
// by default.
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe {
let mut remain = MaybeUninit::<LibcTimespec>::uninit();

Expand All @@ -84,10 +73,7 @@ pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> Nanos
}

// Main version: libc is y2038 safe and has `clock_nanosleep`.
#[cfg(not(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)))]
#[cfg(not(fix_y2038))]
unsafe {
let mut remain = MaybeUninit::<Timespec>::uninit();

Expand All @@ -101,10 +87,8 @@ pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> Nanos
}
}

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
#[cfg(not(target_os = "emscripten"))]
unsafe fn clock_nanosleep_relative_old(id: ClockId, request: &Timespec) -> NanosleepRelativeResult {
let tv_sec = match request.tv_sec.try_into() {
Ok(tv_sec) => tv_sec,
Expand Down Expand Up @@ -154,10 +138,7 @@ pub(crate) fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::R

// 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe
// by default.
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
{
if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() {
match unsafe {
Expand All @@ -177,20 +158,15 @@ pub(crate) fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::R
}

// Main version: libc is y2038 safe and has `clock_nanosleep`.
#[cfg(not(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)))]
#[cfg(not(fix_y2038))]
match unsafe { c::clock_nanosleep(id as c::clockid_t, flags as _, request, null_mut()) } {
0 => Ok(()),
err => Err(io::Errno(err)),
}
}

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
#[cfg(not(target_os = "emscripten"))]
fn clock_nanosleep_absolute_old(id: ClockId, request: &Timespec) -> io::Result<()> {
let flags = c::TIMER_ABSTIME;

Expand All @@ -209,10 +185,7 @@ fn clock_nanosleep_absolute_old(id: ClockId, request: &Timespec) -> io::Result<(
pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult {
// 32-bit gnu version: libc has `nanosleep` but it is not y2038 safe by
// default.
#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe {
let mut remain = MaybeUninit::<LibcTimespec>::uninit();

Expand All @@ -230,10 +203,7 @@ pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult {
}

// Main version: libc is y2038 safe and has `nanosleep`.
#[cfg(not(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
)))]
#[cfg(not(fix_y2038))]
unsafe {
let mut remain = MaybeUninit::<Timespec>::uninit();

Expand All @@ -245,10 +215,7 @@ pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult {
}
}

#[cfg(all(
any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
target_env = "gnu",
))]
#[cfg(fix_y2038)]
unsafe fn nanosleep_old(request: &Timespec) -> NanosleepRelativeResult {
let tv_sec = match request.tv_sec.try_into() {
Ok(tv_sec) => tv_sec,
Expand Down
Loading

0 comments on commit 1595eea

Please sign in to comment.