Skip to content

Commit

Permalink
Auto merge of #975 - christianpoveda:clock-shim, r=RalfJung
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
bors committed Oct 14, 2019
2 parents 2adc39f + f9c7688 commit 5d66fb4
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 1 deletion.
37 changes: 36 additions & 1 deletion src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::mem;

use rustc::ty::{self, layout::{self, Size, Align}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc::mir;
use rustc::ty::{
self,
layout::{self, Align, LayoutOf, Size, TyLayout},
};

use rand::RngCore;

Expand Down Expand Up @@ -304,4 +307,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
self.eval_libc(name)?.to_i32()
}

/// Helper function to get the `TyLayout` of a `libc` type
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> {
let this = self.eval_context_mut();
let tcx = &{ this.tcx.tcx };
let ty = this.resolve_path(&["libc", name])?.ty(*tcx);
this.layout_of(ty)
}

// Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack
// different values into a struct.
fn write_packed_immediates(
&mut self,
place: &MPlaceTy<'tcx, Tag>,
imms: &[ImmTy<'tcx, Tag>],
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();

let tcx = &{ this.tcx.tcx };

let mut offset = Size::from_bytes(0);

for &imm in imms {
this.write_immediate_to_mplace(
*imm,
place.offset(offset, None, imm.layout, tcx)?,
)?;
offset += imm.layout.size;
}

Ok(())
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt};
pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt;
pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt};
pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt};
pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt};
pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt};
Expand Down
10 changes: 10 additions & 0 deletions src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}

"clock_gettime" => {
let result = this.clock_gettime(args[0], args[1])?;
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}

"gettimeofday" => {
let result = this.gettimeofday(args[0], args[1])?;
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
}

"strlen" => {
let ptr = this.read_scalar(args[0])?.not_undef()?;
let n = this.memory().read_c_str(ptr)?.len();
Expand Down
1 change: 1 addition & 0 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
pub mod fs;
pub mod time;

use rustc::{mir, ty};

Expand Down
104 changes: 104 additions & 0 deletions src/shims/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std::time::{Duration, SystemTime};

use rustc::ty::layout::TyLayout;

use crate::stacked_borrows::Tag;
use crate::*;

// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time
// interval
fn get_time<'tcx>() -> InterpResult<'tcx, Duration> {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into())
}

fn int_to_immty_checked<'tcx>(
int: i128,
layout: TyLayout<'tcx>,
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
// If `int` does not fit in `size` bits, we error instead of letting
// `ImmTy::from_int` panic.
let size = layout.size;
let truncated = truncate(int as u128, size);
if sign_extend(truncated, size) as i128 != int {
throw_unsup_format!(
"Signed value {:#x} does not fit in {} bits",
int,
size.bits()
)
}
Ok(ImmTy::from_int(int, layout))
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
// Foreign function used by linux
fn clock_gettime(
&mut self,
clk_id_op: OpTy<'tcx, Tag>,
tp_op: OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();

if !this.machine.communicate {
throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
}

let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
}

let tp = this.deref_operand(tp_op)?;

let duration = get_time()?;
let tv_sec = duration.as_secs() as i128;
let tv_nsec = duration.subsec_nanos() as i128;

let imms = [
int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
];

this.write_packed_immediates(&tp, &imms)?;

Ok(0)
}
// Foreign function used by generic unix (in particular macOS)
fn gettimeofday(
&mut self,
tv_op: OpTy<'tcx, Tag>,
tz_op: OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();

if !this.machine.communicate {
throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
}
// Using tz is obsolete and should always be null
let tz = this.read_scalar(tz_op)?.not_undef()?;
if !this.is_null(tz)? {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
}

let tv = this.deref_operand(tv_op)?;

let duration = get_time()?;
let tv_sec = duration.as_secs() as i128;
let tv_usec = duration.subsec_micros() as i128;

let imms = [
int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
];

this.write_packed_immediates(&tv, &imms)?;

Ok(0)
}
}
8 changes: 8 additions & 0 deletions tests/run-pass/clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// ignore-windows: TODO clock shims are not implemented on Windows
// compile-flags: -Zmiri-disable-isolation

use std::time::SystemTime;

fn main() {
let _now = SystemTime::now();
}

0 comments on commit 5d66fb4

Please sign in to comment.