Skip to content

Commit ee967c1

Browse files
committed
Auto merge of #1286 - JOE1994:windows_time, r=RalfJung
Implement 'GetSystemTimeAsFileTime' shim for Windows Implement `GetSystemTimeAsFileTime` shim for Windows. Closes #997
2 parents 552775b + b3f9e53 commit ee967c1

File tree

5 files changed

+73
-21
lines changed

5 files changed

+73
-21
lines changed

src/helpers.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
7373
.not_undef()
7474
}
7575

76+
/// Helper function to get a `libc` constant as an `i32`.
77+
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
78+
// TODO: Cache the result.
79+
self.eval_libc(name)?.to_i32()
80+
}
81+
7682
/// Helper function to get a `windows` constant as a `Scalar`.
77-
fn eval_windows(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
83+
fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
7884
self.eval_context_mut()
79-
.eval_path_scalar(&["std", "sys", "windows", "c", name])?
85+
.eval_path_scalar(&["std", "sys", "windows", module, name])?
8086
.not_undef()
8187
}
8288

83-
/// Helper function to get a `libc` constant as an `i32`.
84-
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
89+
/// Helper function to get a `windows` constant as an `u64`.
90+
fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
8591
// TODO: Cache the result.
86-
self.eval_libc(name)?.to_i32()
92+
self.eval_windows(module, name)?.to_u64()
8793
}
8894

8995
/// Helper function to get the `TyAndLayout` of a `libc` type
@@ -93,6 +99,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9399
this.layout_of(ty)
94100
}
95101

102+
/// Helper function to get the `TyAndLayout` of a `windows` type
103+
fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
104+
let this = self.eval_context_mut();
105+
let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx);
106+
this.layout_of(ty)
107+
}
108+
96109
/// Write a 0 of the appropriate size to `dest`.
97110
fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
98111
self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
@@ -350,7 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
350363
}
351364
}
352365

353-
// Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack
366+
// Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack
354367
// different values into a struct.
355368
fn write_packed_immediates(
356369
&mut self,
@@ -439,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
439452
})?
440453
} else if target_os == "windows" {
441454
// FIXME: we have to finish implementing the Windows equivalent of this.
442-
this.eval_windows(match e.kind() {
455+
this.eval_windows("c", match e.kind() {
443456
NotFound => "ERROR_FILE_NOT_FOUND",
444457
_ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e)
445458
})?

src/shims/env.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
143143
windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?)
144144
}
145145
None => {
146-
let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?;
146+
let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND")?;
147147
this.set_last_error(envvar_not_found)?;
148148
0 // return zero upon failure
149149
}

src/shims/foreign_items/windows.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
167167
)?;
168168
}
169169

170+
// Time related shims
171+
"GetSystemTimeAsFileTime" => {
172+
this.GetSystemTimeAsFileTime(args[0])?;
173+
}
174+
170175
// Miscellaneous
171176
"SystemFunction036" => {
172177
// The actual name of 'RtlGenRandom'

src/shims/time.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use std::convert::TryFrom;
33

44
use crate::stacked_borrows::Tag;
55
use crate::*;
6-
use helpers::immty_from_int_checked;
6+
use helpers::{immty_from_int_checked, immty_from_uint_checked};
7+
8+
use rustc_middle::ty::layout::LayoutOf;
79

810
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
911
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
@@ -85,6 +87,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8587
Ok(0)
8688
}
8789

90+
#[allow(non_snake_case)]
91+
fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
92+
let this = self.eval_context_mut();
93+
94+
this.assert_target_os("windows", "GetSystemTimeAsFileTime");
95+
this.check_no_isolation("GetSystemTimeAsFileTime")?;
96+
97+
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
98+
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
99+
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
100+
let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
101+
let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
102+
103+
let duration = system_time_to_duration(&SystemTime::now())?
104+
.checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
105+
.unwrap();
106+
let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
107+
.map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?;
108+
109+
let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
110+
let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
111+
let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
112+
let imms = [
113+
immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
114+
immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
115+
];
116+
this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
117+
Ok(())
118+
}
119+
88120
fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
89121
let this = self.eval_context_ref();
90122

tests/run-pass/time.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// ignore-windows: TODO clock shims are not implemented on Windows
21
// compile-flags: -Zmiri-disable-isolation
32

43
use std::time::{SystemTime, Instant};
@@ -14,17 +13,20 @@ fn main() {
1413
assert_eq!(now1 + diff, now2);
1514
assert_eq!(now2 - diff, now1);
1615

17-
let now1 = Instant::now();
18-
// Do some work to make time pass.
19-
for _ in 0..10 { drop(vec![42]); }
20-
let now2 = Instant::now();
21-
assert!(now2 > now1);
22-
23-
#[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction
16+
#[cfg(not(windows))] // `Instant` shims not yet implemented on Windows
2417
{
25-
let diff = now2.duration_since(now1);
26-
assert!(diff.as_micros() > 0);
27-
assert_eq!(now1 + diff, now2);
28-
assert_eq!(now2 - diff, now1);
18+
let now1 = Instant::now();
19+
// Do some work to make time pass.
20+
for _ in 0..10 { drop(vec![42]); }
21+
let now2 = Instant::now();
22+
assert!(now2 > now1);
23+
24+
#[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction
25+
{
26+
let diff = now2.duration_since(now1);
27+
assert!(diff.as_micros() > 0);
28+
assert_eq!(now1 + diff, now2);
29+
assert_eq!(now2 - diff, now1);
30+
}
2931
}
3032
}

0 commit comments

Comments
 (0)