Auto merge of #3523 - saethlin:localtime_r-env, r=RalfJung
Use the interpreted program's TZ variable in localtime_r This requires a bit of wiring and a new dependency, but the tests should correctly pass now regardless of what the host's time zone is. Fixes https://github.com/rust-lang/miri/issues/3522
This commit is contained in:
commit
1c7e82762f
@ -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"
|
||||
|
@ -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`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::ffi::OsString;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
@ -99,4 +99,15 @@ pub(crate) fn windows_mut(&mut self) -> &mut WindowsEnvVars {
|
||||
}
|
||||
|
||||
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<OsString>> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ fn localtime_r(
|
||||
.unwrap();
|
||||
let dt_utc: DateTime<Utc> =
|
||||
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<Local> = DateTime::from(dt_utc);
|
||||
let dt: DateTime<Tz> = 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 @@ fn localtime_r(
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
@ -70,6 +70,41 @@ pub(crate) fn cleanup<'mir>(
|
||||
pub(crate) fn environ(&self) -> Pointer<Option<Provenance>> {
|
||||
self.environ.ptr()
|
||||
}
|
||||
|
||||
fn get_ptr<'mir>(
|
||||
&self,
|
||||
ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
|
||||
name: &OsStr,
|
||||
) -> InterpResult<'tcx, Option<Pointer<Option<Provenance>>>> {
|
||||
// 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<OsString>> {
|
||||
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 @@ fn getenv(
|
||||
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(
|
||||
|
@ -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 @@
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WindowsEnvVars {
|
||||
/// Stores the environment varialbles.
|
||||
/// Stores the environment variables.
|
||||
map: FxHashMap<OsString, OsString>,
|
||||
}
|
||||
|
||||
@ -26,6 +26,11 @@ pub(crate) fn new<'mir, 'tcx>(
|
||||
) -> 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<OsString>> {
|
||||
Ok(self.map.get(name).cloned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
|
||||
|
Loading…
Reference in New Issue
Block a user