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`.
This commit is contained in:
bors 2019-10-15 07:36:42 +00:00
commit d902a11575
6 changed files with 160 additions and 1 deletions

View File

@ -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;
@ -304,4 +307,36 @@ fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
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(())
}
}

View File

@ -32,6 +32,7 @@
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};

View File

@ -507,6 +507,16 @@ fn emulate_foreign_item(
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();

View File

@ -4,6 +4,7 @@
pub mod intrinsics;
pub mod tls;
pub mod fs;
pub mod time;
use rustc::{mir, ty};

104
src/shims/time.rs Normal file
View File

@ -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
tests/run-pass/clock.rs Normal file
View File

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