Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clock_gettime shim #975

Merged
merged 13 commits into from
Oct 15, 2019
41 changes: 40 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},
};
pvdrz marked this conversation as resolved.
Show resolved Hide resolved

use rand::RngCore;

Expand Down Expand Up @@ -304,4 +307,40 @@ 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_immediates(
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
ptr: &Pointer<Tag>,
imms: &[ImmTy<'tcx, Tag>],
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();

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

let allocation = this.memory_mut().get_mut(ptr.alloc_id)?;
let mut offset = Size::from_bytes(0);

for imm in imms {
let size = imm.layout.size;
allocation.write_scalar(
tcx,
ptr.offset(offset, tcx)?,
imm.to_scalar()?.into(),
size,
)?;
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
offset += 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
117 changes: 117 additions & 0 deletions src/shims/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
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() -> (Duration, i128) {
let mut sign = 1;
let duration = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_else(|e| {
sign = -1;
e.duration()
});
(duration, sign)
}

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.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?;

let (duration, sign) = get_time();
let tv_sec = sign * (duration.as_secs() as i128);
let mut tv_nsec = duration.subsec_nanos() as i128;
// If the number of seconds is zero, we need to put the sign into the second's fraction.
if tv_sec == 0 && sign < 0 {
tv_nsec *= sign;
}
pvdrz marked this conversation as resolved.
Show resolved Hide resolved

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_immediates(&tp, &imms)?;

Ok(0)
}
// Foreign function used by generic unix
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
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.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?;

let (duration, sign) = get_time();
let tv_sec = sign * (duration.as_secs() as i128);
let mut tv_usec = duration.subsec_micros() as i128;
// If the number of seconds is zero, we need to put the sign into the second's fraction.
if tv_sec == 0 && sign < 0 {
tv_usec *= sign;
}
pvdrz marked this conversation as resolved.
Show resolved Hide resolved

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_immediates(&tv, &imms)?;

Ok(0)
}
}
7 changes: 7 additions & 0 deletions tests/run-pass/clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// compile-flags: -Zmiri-disable-isolation

use std::time::SystemTime;

fn main() {
let _now = SystemTime::now();
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
}