Skip to content
Merged
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},
};

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(
&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,
)?;
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;
}

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
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;
}

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();
}