From 3f638a92917ecbf43e4dda6fe8dd97f2209e5532 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 18 May 2024 23:14:14 +0000 Subject: [PATCH] solaris/illumos localtime_r / clock_getime support enabled. clock_gettime support CLOCK_REALTIME/CLOCK_MONOTONIC clockid_t. localtime_r is supported only tm struct is more limited than other supported platforms. --- src/tools/miri/ci/ci.sh | 4 +- src/tools/miri/src/shims/time.rs | 64 +++++++++++-------- .../miri/tests/pass-dep/libc/libc-time.rs | 5 +- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 4e92169b3d05d..96319c0959c9d 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -148,8 +148,8 @@ case $HOST_TARGET in UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX pthread-sync - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX pthread-sync + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX pthread-sync libc-time + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX pthread-sync libc-time TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 8d1f07f916c9b..941c61caa53ab 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -62,6 +62,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We need to support it because std uses it. relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")); } + "solaris" | "illumos" => { + // The REALTIME clock returns the actual time since the Unix epoch. + absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")]; + // MONOTONIC, in the other hand, is the high resolution, non-adjustable + // clock from an arbitrary time in the past. + // Note that the man page mentions HIGHRES but it is just + // an alias of MONOTONIC and the libc crate does not expose it anyway. + // https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html + relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")]; + } target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"), } @@ -153,30 +163,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // chrono crate yet. // This may not be consistent with libc::localtime_r's result. let tm_isdst = -1; - - // tm_zone represents the timezone value in the form of: +0730, +08, -0730 or -08. - // This may not be consistent with libc::localtime_r's result. - let offset_in_seconds = dt.offset().fix().local_minus_utc(); - let tm_gmtoff = offset_in_seconds; - let mut tm_zone = String::new(); - if offset_in_seconds < 0 { - tm_zone.push('-'); - } else { - tm_zone.push('+'); - } - let offset_hour = offset_in_seconds.abs() / 3600; - write!(tm_zone, "{:02}", offset_hour).unwrap(); - let offset_min = (offset_in_seconds.abs() % 3600) / 60; - if offset_min != 0 { - write!(tm_zone, "{:02}", offset_min).unwrap(); - } - - // FIXME: String de-duplication is needed so that we only allocate this string only once - // even when there are multiple calls to this function. - let tm_zone_ptr = - this.alloc_os_str_as_c_str(&OsString::from(tm_zone), MiriMemoryKind::Machine.into())?; - - this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; this.write_int_fields_named( &[ ("tm_sec", dt.second().into()), @@ -188,11 +174,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ("tm_wday", dt.weekday().num_days_from_sunday().into()), ("tm_yday", dt.ordinal0().into()), ("tm_isdst", tm_isdst), - ("tm_gmtoff", tm_gmtoff.into()), ], &result, )?; + // solaris/illumos system tm struct does not have + // the additional tm_zone/tm_gmtoff fields. + // https://docs.oracle.com/cd/E36784_01/html/E36874/localtime-r-3c.html + if !matches!(&*this.tcx.sess.target.os, "solaris" | "illumos") { + // tm_zone represents the timezone value in the form of: +0730, +08, -0730 or -08. + // This may not be consistent with libc::localtime_r's result. + let offset_in_seconds = dt.offset().fix().local_minus_utc(); + let tm_gmtoff = offset_in_seconds; + let mut tm_zone = String::new(); + if offset_in_seconds < 0 { + tm_zone.push('-'); + } else { + tm_zone.push('+'); + } + let offset_hour = offset_in_seconds.abs() / 3600; + write!(tm_zone, "{:02}", offset_hour).unwrap(); + let offset_min = (offset_in_seconds.abs() % 3600) / 60; + if offset_min != 0 { + write!(tm_zone, "{:02}", offset_min).unwrap(); + } + + // FIXME: String de-duplication is needed so that we only allocate this string only once + // even when there are multiple calls to this function. + let tm_zone_ptr = this + .alloc_os_str_as_c_str(&OsString::from(tm_zone), MiriMemoryKind::Machine.into())?; + + this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; + this.write_int_fields_named(&[("tm_gmtoff", tm_gmtoff.into())], &result)?; + } Ok(result.ptr()) } #[allow(non_snake_case, clippy::arithmetic_side_effects)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index ea1e49a072571..5e4bb73e36883 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,6 +1,5 @@ //@ignore-target-windows: no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation -use std::ffi::CStr; use std::{env, mem, ptr}; fn main() { @@ -64,7 +63,9 @@ fn test_localtime_r() { tm_wday: 0, tm_yday: 0, tm_isdst: 0, + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] tm_gmtoff: 0, + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] tm_zone: std::ptr::null_mut::(), }; let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; @@ -82,7 +83,7 @@ fn test_localtime_r() { assert_eq!(tm.tm_gmtoff, 0); #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] unsafe { - assert_eq!(CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") + assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") }; // The returned value is the pointer passed in.