diff --git a/Cargo.lock b/Cargo.lock index 293b937a5e..3a282e8931 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,21 +37,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "annotate-snippets" version = "0.9.2" @@ -121,12 +106,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - [[package]] name = "camino" version = "1.1.6" @@ -177,10 +156,29 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "android-tzdata", - "iana-time-zone", "num-traits", - "windows-targets 0.52.3", +] + +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", ] [[package]] @@ -249,12 +247,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - [[package]] name = "cpufeatures" version = "0.2.12" @@ -379,29 +371,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "indenter" version = "0.3.3" @@ -455,15 +424,6 @@ dependencies = [ "libc", ] -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -587,6 +547,7 @@ version = "0.1.0" dependencies = [ "aes", "chrono", + "chrono-tz", "colored", "ctrlc", "directories", @@ -690,6 +651,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "perf-event-open-sys" version = "3.0.0" @@ -699,6 +669,44 @@ dependencies = [ "libc", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -931,6 +939,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "smallvec" version = "1.13.1" @@ -1094,60 +1108,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - [[package]] name = "winapi" version = "0.3.9" @@ -1170,15 +1130,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.3", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index b00dae784d..de7a6de9e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,8 @@ smallvec = "1.7" aes = { version = "0.8.3", features = ["hazmat"] } measureme = "11" ctrlc = "3.2.5" -chrono = { version = "0.4.38", default-features = false, features = ["clock"] } +chrono = { version = "0.4.38", default-features = false } +chrono-tz = "0.9" directories = "5" # Copied from `compiler/rustc/Cargo.toml`. diff --git a/src/shims/env.rs b/src/shims/env.rs index fc0160fdf2..695d113875 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,4 @@ -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use rustc_data_structures::fx::FxHashMap; @@ -99,4 +99,15 @@ impl<'tcx> EnvVars<'tcx> { } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Try to get an environment variable from the interpreted program's environment. This is + /// useful for implementing shims which are documented to read from the environment. + fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { + let this = self.eval_context_ref(); + match &this.machine.env_vars { + EnvVars::Uninit => return Ok(None), + EnvVars::Unix(vars) => vars.get(this, name), + EnvVars::Windows(vars) => vars.get(name), + } + } +} diff --git a/src/shims/time.rs b/src/shims/time.rs index dfdf58470d..8d1f07f916 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,10 @@ -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fmt::Write; +use std::str::FromStr; use std::time::{Duration, SystemTime}; -use chrono::{DateTime, Datelike, Local, Timelike, Utc}; +use chrono::{DateTime, Datelike, Offset, Timelike, Utc}; +use chrono_tz::Tz; use crate::concurrency::thread::MachineCallback; use crate::*; @@ -136,8 +138,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .unwrap(); let dt_utc: DateTime = DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); + + // Figure out what time zone is in use + let tz = this.get_env_var(OsStr::new("TZ"))?.unwrap_or_else(|| OsString::from("UTC")); + let tz = match tz.into_string() { + Ok(tz) => Tz::from_str(&tz).unwrap_or(Tz::UTC), + _ => Tz::UTC, + }; + // Convert that to local time, then return the broken-down time value. - let dt: DateTime = DateTime::from(dt_utc); + let dt: DateTime = dt_utc.with_timezone(&tz); // This value is always set to -1, because there is no way to know if dst is in effect with // chrono crate yet. @@ -146,17 +156,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // 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_second = Local::now().offset().local_minus_utc(); - let tm_gmtoff = offset_in_second; + 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_second < 0 { + if offset_in_seconds < 0 { tm_zone.push('-'); } else { tm_zone.push('+'); } - let offset_hour = offset_in_second.abs() / 3600; + let offset_hour = offset_in_seconds.abs() / 3600; write!(tm_zone, "{:02}", offset_hour).unwrap(); - let offset_min = (offset_in_second.abs() % 3600) / 60; + let offset_min = (offset_in_seconds.abs() % 3600) / 60; if offset_min != 0 { write!(tm_zone, "{:02}", offset_min).unwrap(); } diff --git a/src/shims/unix/env.rs b/src/shims/unix/env.rs index 128f0dcafa..9082d13da8 100644 --- a/src/shims/unix/env.rs +++ b/src/shims/unix/env.rs @@ -70,6 +70,41 @@ impl<'tcx> UnixEnvVars<'tcx> { pub(crate) fn environ(&self) -> Pointer> { self.environ.ptr() } + + fn get_ptr<'mir>( + &self, + ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + ) -> InterpResult<'tcx, Option>>> { + // We don't care about the value as we have the `map` to keep track of everything, + // but we do want to do this read so it shows up as a data race. + let _vars_ptr = ecx.read_pointer(&self.environ)?; + let Some(var_ptr) = self.map.get(name) else { + return Ok(None); + }; + // The offset is used to strip the "{name}=" part of the string. + let var_ptr = var_ptr.offset( + Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), + ecx, + )?; + Ok(Some(var_ptr)) + } + + /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete + /// with the reads of the environment, but returns an [`OsString`] instead of a pointer. + pub(crate) fn get<'mir>( + &self, + ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, + name: &OsStr, + ) -> InterpResult<'tcx, Option> { + let var_ptr = self.get_ptr(ecx, name)?; + if let Some(ptr) = var_ptr { + let var = ecx.read_os_str_from_c_str(ptr)?; + Ok(Some(var.to_owned())) + } else { + Ok(None) + } + } } fn alloc_env_var<'mir, 'tcx>( @@ -116,19 +151,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; - // We don't care about the value as we have the `map` to keep track of everything, - // but we do want to do this read so it shows up as a data race. - let _vars_ptr = this.read_pointer(&this.machine.env_vars.unix().environ)?; - Ok(match this.machine.env_vars.unix().map.get(name) { - Some(var_ptr) => { - // The offset is used to strip the "{name}=" part of the string. - var_ptr.offset( - Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), - this, - )? - } - None => Pointer::null(), - }) + let var_ptr = this.machine.env_vars.unix().get_ptr(this, name)?; + Ok(var_ptr.unwrap_or_else(Pointer::null)) } fn setenv( diff --git a/src/shims/windows/env.rs b/src/shims/windows/env.rs index e91623ac87..b3bc5d4d85 100644 --- a/src/shims/windows/env.rs +++ b/src/shims/windows/env.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; @@ -9,7 +9,7 @@ use helpers::windows_check_buffer_size; #[derive(Default)] pub struct WindowsEnvVars { - /// Stores the environment varialbles. + /// Stores the environment variables. map: FxHashMap, } @@ -26,6 +26,11 @@ impl WindowsEnvVars { ) -> InterpResult<'tcx, Self> { Ok(Self { map: env_vars }) } + + /// Implementation detail for [`InterpCx::get_env_var`]. + pub(crate) fn get<'tcx>(&self, name: &OsStr) -> InterpResult<'tcx, Option> { + Ok(self.map.get(name).cloned()) + } } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}