Skip to content

Commit d902a11

Browse files
committed
Auto merge of #975 - christianpoveda:clock-shim, r=RalfJung
Add clock_gettime shim r? @oli-obk I think there is no way to do proper testing of this other than checking that miri does not crash when calling `clock_gettime`.
2 parents 2adc39f + f9c7688 commit d902a11

File tree

6 files changed

+160
-1
lines changed

6 files changed

+160
-1
lines changed

src/helpers.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use std::mem;
22

3-
use rustc::ty::{self, layout::{self, Size, Align}};
43
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
54
use rustc::mir;
5+
use rustc::ty::{
6+
self,
7+
layout::{self, Align, LayoutOf, Size, TyLayout},
8+
};
69

710
use rand::RngCore;
811

@@ -304,4 +307,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
304307
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
305308
self.eval_libc(name)?.to_i32()
306309
}
310+
311+
/// Helper function to get the `TyLayout` of a `libc` type
312+
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> {
313+
let this = self.eval_context_mut();
314+
let tcx = &{ this.tcx.tcx };
315+
let ty = this.resolve_path(&["libc", name])?.ty(*tcx);
316+
this.layout_of(ty)
317+
}
318+
319+
// Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack
320+
// different values into a struct.
321+
fn write_packed_immediates(
322+
&mut self,
323+
place: &MPlaceTy<'tcx, Tag>,
324+
imms: &[ImmTy<'tcx, Tag>],
325+
) -> InterpResult<'tcx> {
326+
let this = self.eval_context_mut();
327+
328+
let tcx = &{ this.tcx.tcx };
329+
330+
let mut offset = Size::from_bytes(0);
331+
332+
for &imm in imms {
333+
this.write_immediate_to_mplace(
334+
*imm,
335+
place.offset(offset, None, imm.layout, tcx)?,
336+
)?;
337+
offset += imm.layout.size;
338+
}
339+
340+
Ok(())
341+
}
307342
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt};
3232
pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt;
3333
pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
3434
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
35+
pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt};
3536
pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt};
3637
pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt};
3738
pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt};

src/shims/foreign_items.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
507507
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
508508
}
509509

510+
"clock_gettime" => {
511+
let result = this.clock_gettime(args[0], args[1])?;
512+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
513+
}
514+
515+
"gettimeofday" => {
516+
let result = this.gettimeofday(args[0], args[1])?;
517+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
518+
}
519+
510520
"strlen" => {
511521
let ptr = this.read_scalar(args[0])?.not_undef()?;
512522
let n = this.memory().read_c_str(ptr)?.len();

src/shims/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod foreign_items;
44
pub mod intrinsics;
55
pub mod tls;
66
pub mod fs;
7+
pub mod time;
78

89
use rustc::{mir, ty};
910

src/shims/time.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use std::time::{Duration, SystemTime};
2+
3+
use rustc::ty::layout::TyLayout;
4+
5+
use crate::stacked_borrows::Tag;
6+
use crate::*;
7+
8+
// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time
9+
// interval
10+
fn get_time<'tcx>() -> InterpResult<'tcx, Duration> {
11+
SystemTime::now()
12+
.duration_since(SystemTime::UNIX_EPOCH)
13+
.map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into())
14+
}
15+
16+
fn int_to_immty_checked<'tcx>(
17+
int: i128,
18+
layout: TyLayout<'tcx>,
19+
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
20+
// If `int` does not fit in `size` bits, we error instead of letting
21+
// `ImmTy::from_int` panic.
22+
let size = layout.size;
23+
let truncated = truncate(int as u128, size);
24+
if sign_extend(truncated, size) as i128 != int {
25+
throw_unsup_format!(
26+
"Signed value {:#x} does not fit in {} bits",
27+
int,
28+
size.bits()
29+
)
30+
}
31+
Ok(ImmTy::from_int(int, layout))
32+
}
33+
34+
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
35+
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
36+
// Foreign function used by linux
37+
fn clock_gettime(
38+
&mut self,
39+
clk_id_op: OpTy<'tcx, Tag>,
40+
tp_op: OpTy<'tcx, Tag>,
41+
) -> InterpResult<'tcx, i32> {
42+
let this = self.eval_context_mut();
43+
44+
if !this.machine.communicate {
45+
throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
46+
}
47+
48+
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
49+
if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
50+
let einval = this.eval_libc("EINVAL")?;
51+
this.set_last_error(einval)?;
52+
return Ok(-1);
53+
}
54+
55+
let tp = this.deref_operand(tp_op)?;
56+
57+
let duration = get_time()?;
58+
let tv_sec = duration.as_secs() as i128;
59+
let tv_nsec = duration.subsec_nanos() as i128;
60+
61+
let imms = [
62+
int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
63+
int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
64+
];
65+
66+
this.write_packed_immediates(&tp, &imms)?;
67+
68+
Ok(0)
69+
}
70+
// Foreign function used by generic unix (in particular macOS)
71+
fn gettimeofday(
72+
&mut self,
73+
tv_op: OpTy<'tcx, Tag>,
74+
tz_op: OpTy<'tcx, Tag>,
75+
) -> InterpResult<'tcx, i32> {
76+
let this = self.eval_context_mut();
77+
78+
if !this.machine.communicate {
79+
throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
80+
}
81+
// Using tz is obsolete and should always be null
82+
let tz = this.read_scalar(tz_op)?.not_undef()?;
83+
if !this.is_null(tz)? {
84+
let einval = this.eval_libc("EINVAL")?;
85+
this.set_last_error(einval)?;
86+
return Ok(-1);
87+
}
88+
89+
let tv = this.deref_operand(tv_op)?;
90+
91+
let duration = get_time()?;
92+
let tv_sec = duration.as_secs() as i128;
93+
let tv_usec = duration.subsec_micros() as i128;
94+
95+
let imms = [
96+
int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
97+
int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
98+
];
99+
100+
this.write_packed_immediates(&tv, &imms)?;
101+
102+
Ok(0)
103+
}
104+
}

tests/run-pass/clock.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// ignore-windows: TODO clock shims are not implemented on Windows
2+
// compile-flags: -Zmiri-disable-isolation
3+
4+
use std::time::SystemTime;
5+
6+
fn main() {
7+
let _now = SystemTime::now();
8+
}

0 commit comments

Comments
 (0)