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:
commit
d902a11575
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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();
|
||||
|
@ -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
104
src/shims/time.rs
Normal 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
8
tests/run-pass/clock.rs
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user