From aa3e9703d180648af483a4d2304a9092debf365d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 13:17:58 -0500 Subject: [PATCH 01/13] Add clock_gettime shim --- src/shims/foreign_items.rs | 55 ++++++++++++++++++++++++++++++++------ tests/run-pass/clock.rs | 7 +++++ 2 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/clock.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 00160156312..8641a7cf386 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -507,16 +507,55 @@ fn emulate_foreign_item( 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(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + "clock_gettime" => { + if !this.machine.communicate { + throw_unsup_format!("`clock_gettime` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let clk_id = this.read_scalar(args[0])?.to_i32()?; + + if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|_| bug!("Clock went backwards")); + + allocation.write_scalar( + tcx, + tp, + Scalar::from_u64(duration.as_secs()).into(), + Size::from_bits(64), + )?; + allocation.write_scalar( + tcx, + tp.offset(Size::from_bits(64), tcx)?, + Scalar::from_u64(duration.subsec_nanos() as u64).into(), + Size::from_bits(64), + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } + + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs new file mode 100644 index 00000000000..987a78fe1f0 --- /dev/null +++ b/tests/run-pass/clock.rs @@ -0,0 +1,7 @@ +// compile-flags: -Zmiri-disable-isolation + +use std::time::SystemTime; + +fn main() { + let _now = SystemTime::now(); +} From fcf04b5425099738c0f26994baf29a1112997bf2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 11:20:06 -0500 Subject: [PATCH 02/13] Reduce size of nanoseconds --- src/shims/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8641a7cf386..c106a296dcd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -537,8 +537,8 @@ fn emulate_foreign_item( allocation.write_scalar( tcx, tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u64(duration.subsec_nanos() as u64).into(), - Size::from_bits(64), + Scalar::from_u32(duration.subsec_nanos()).into(), + Size::from_bits(32), )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From adfa2eb062bf825bb100dc2cfd7ab7df075f1824 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 16:22:53 -0500 Subject: [PATCH 03/13] Return negative times when the current time is before the unix epoch --- src/shims/foreign_items.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c106a296dcd..c403afacd89 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -524,21 +524,30 @@ fn emulate_foreign_item( let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + let mut sign = 1; + let duration = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| bug!("Clock went backwards")); + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + let tv_sec_size = Size::from_bits(64); + let tv_nsec_size = Size::from_bits(64); allocation.write_scalar( tcx, tp, - Scalar::from_u64(duration.as_secs()).into(), - Size::from_bits(64), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + tv_sec_size, )?; + allocation.write_scalar( tcx, - tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u32(duration.subsec_nanos()).into(), - Size::from_bits(32), + tp.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), + tv_nsec_size, )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From 7a6df8504f477faafe1c91e0c7fa83a63e31a825 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 13:29:39 -0500 Subject: [PATCH 04/13] Get size of integers using libc --- src/shims/foreign_items.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c403afacd89..1e7c85c4352 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -522,6 +522,12 @@ fn emulate_foreign_item( } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_nsec_size = this.layout_of(long)?.size; + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; let mut sign = 1; @@ -533,13 +539,11 @@ fn emulate_foreign_item( e.duration() }); - let tv_sec_size = Size::from_bits(64); - let tv_nsec_size = Size::from_bits(64); - allocation.write_scalar( tcx, tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), tv_sec_size, )?; @@ -555,16 +559,16 @@ fn emulate_foreign_item( } } - "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; - } + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), From b7863f2509eed16f2ce79ffb52a21de5bd536a48 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 14:04:23 -0500 Subject: [PATCH 05/13] Add gettimeofday shim for macOS --- src/shims/foreign_items.rs | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1e7c85c4352..656cb010102 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -559,6 +559,58 @@ fn emulate_foreign_item( } } + "gettimeofday" => { + if !this.machine.communicate { + throw_unsup_format!("`gettimeofday` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let tz = this.read_scalar(args[1])?.not_undef()?; + // Using tz is obsolete and should always be null + if !this.is_null(tz)? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; + + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_usec_size = this.layout_of(suseconds_t)?.size; + + let allocation = this.memory_mut().get_mut(tv.alloc_id)?; + + let mut sign = 1; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + allocation.write_scalar( + tcx, + tv, + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), + tv_sec_size, + )?; + + allocation.write_scalar( + tcx, + tv.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), + tv_usec_size, + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory().read_c_str(ptr)?.len(); From 9f24c126249990f337f7e940b586a1424081d9c6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 15:06:14 -0500 Subject: [PATCH 06/13] Add helper function to write structs --- src/helpers.rs | 38 +++++++++++++++++++++++++++- src/shims/foreign_items.rs | 52 +++++--------------------------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c7b7853388c..eeada36ca83 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -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, Size, LayoutOf}, +}; use rand::RngCore; @@ -304,4 +307,37 @@ fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name)?.to_i32() } + + fn write_c_ints( + &mut self, + ptr: &Pointer, + bits: &[i128], + ty_names: &[&str], + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let tcx = &{ this.tcx.tcx }; + + let mut sizes = Vec::new(); + + for name in ty_names { + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + sizes.push(this.layout_of(ty)?.size); + } + + let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; + let mut offset = Size::from_bytes(0); + + for (value, size) in bits.iter().zip(sizes) { + allocation.write_scalar( + tcx, + ptr.offset(offset, tcx)?, + Scalar::from_int(*value, size).into(), + size, + )?; + offset += size; + } + + Ok(()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 656cb010102..edf151f44ef 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -511,8 +511,6 @@ fn emulate_foreign_item( if !this.machine.communicate { throw_unsup_format!("`clock_gettime` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let clk_id = this.read_scalar(args[0])?.to_i32()?; if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { @@ -522,14 +520,6 @@ fn emulate_foreign_item( } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_nsec_size = this.layout_of(long)?.size; - - let allocation = this.memory_mut().get_mut(tp.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -539,20 +529,10 @@ fn emulate_foreign_item( e.duration() }); - allocation.write_scalar( - tcx, - tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_nsec = duration.subsec_nanos() as i128; - allocation.write_scalar( - tcx, - tp.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), - tv_nsec_size, - )?; + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } @@ -563,8 +543,6 @@ fn emulate_foreign_item( if !this.machine.communicate { throw_unsup_format!("`gettimeofday` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let tz = this.read_scalar(args[1])?.not_undef()?; // Using tz is obsolete and should always be null if !this.is_null(tz)? { @@ -574,14 +552,6 @@ fn emulate_foreign_item( } else { let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_usec_size = this.layout_of(suseconds_t)?.size; - - let allocation = this.memory_mut().get_mut(tv.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -591,20 +561,10 @@ fn emulate_foreign_item( e.duration() }); - allocation.write_scalar( - tcx, - tv, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_usec = duration.subsec_micros() as i128; - allocation.write_scalar( - tcx, - tv.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), - tv_usec_size, - )?; + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } From b8ee90d22eff95f02d78f628e4f2c3b71e265f1a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 9 Oct 2019 10:56:47 -0500 Subject: [PATCH 07/13] Throw error instead of panicking for unfittable bits --- src/helpers.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index eeada36ca83..fea2307dcca 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, Size, LayoutOf}, + layout::{self, Align, LayoutOf, Size}, }; use rand::RngCore; @@ -328,11 +328,22 @@ fn write_c_ints( let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (value, size) in bits.iter().zip(sizes) { + for (&value, size) in bits.iter().zip(sizes) { + // If `value` does not fit in `size` bits, we error instead of letting + // `Scalar::from_int` panic. + let truncated = truncate(value as u128, size); + if sign_extend(truncated, size) as i128 != value { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + value, + size.bits() + ) + } + allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(*value, size).into(), + Scalar::from_int(value, size).into(), size, )?; offset += size; From 8f4d185d1b39b98846895b06d4a29525365eba4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 10 Oct 2019 15:41:32 -0500 Subject: [PATCH 08/13] Move time related functions to its own module --- src/lib.rs | 1 + src/shims/foreign_items.rs | 62 ++----------------------------- src/shims/mod.rs | 1 + src/shims/time.rs | 75 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 src/shims/time.rs diff --git a/src/lib.rs b/src/lib.rs index baae26d91ad..06ec33a914b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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}; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index edf151f44ef..f6195961ba0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -508,67 +508,13 @@ fn emulate_foreign_item( } "clock_gettime" => { - if !this.machine.communicate { - throw_unsup_format!("`clock_gettime` not available when isolation is enabled") - } else { - let clk_id = this.read_scalar(args[0])?.to_i32()?; - - if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() as i128; - - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.clock_gettime(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "gettimeofday" => { - if !this.machine.communicate { - throw_unsup_format!("`gettimeofday` not available when isolation is enabled") - } else { - let tz = this.read_scalar(args[1])?.not_undef()?; - // Using tz is obsolete and should always be null - if !this.is_null(tz)? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() as i128; - - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.gettimeofday(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "strlen" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 6d80af46850..95bb8b70370 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -4,6 +4,7 @@ pub mod intrinsics; pub mod tls; pub mod fs; +pub mod time; use rustc::{mir, ty}; diff --git a/src/shims/time.rs b/src/shims/time.rs new file mode 100644 index 00000000000..97b74542d80 --- /dev/null +++ b/src/shims/time.rs @@ -0,0 +1,75 @@ +use crate::stacked_borrows::Tag; +use crate::*; + +use std::time::{Duration, SystemTime}; + +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) +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + 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 tv_nsec = duration.subsec_nanos() as i128; + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + + Ok(0) + } + + 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 tv_usec = duration.subsec_micros() as i128; + + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + + Ok(0) + } +} From 87b210df6c4ee3cd823f3d0a4a6940084e765c82 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:03:54 -0500 Subject: [PATCH 09/13] Fix sign when number of seconds is zero --- src/shims/time.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 97b74542d80..2995bdc4346 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,7 @@ fn get_time() -> (Duration, i128) { 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>, @@ -38,12 +39,17 @@ fn clock_gettime( let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() 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; + } + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; Ok(0) } - + // Foreign function used by generic unix fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -66,7 +72,11 @@ fn gettimeofday( let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() 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; + } this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; From 2cbf4afa99a1a8953ed54abdcb292b45b79a8639 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:55:32 -0500 Subject: [PATCH 10/13] Split `write_c_ints` into less specific helper functions --- src/helpers.rs | 39 +++++++++++++++------------------------ src/shims/time.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index fea2307dcca..892ba7b2401 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, LayoutOf, Size}, + layout::{self, Align, LayoutOf, Size, TyLayout}, }; use rand::RngCore; @@ -308,42 +308,26 @@ fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name)?.to_i32() } - fn write_c_ints( + // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack + // different values into an struct. + fn write_immediates( &mut self, ptr: &Pointer, - bits: &[i128], - ty_names: &[&str], + imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; - let mut sizes = Vec::new(); - - for name in ty_names { - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); - sizes.push(this.layout_of(ty)?.size); - } - let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (&value, size) in bits.iter().zip(sizes) { - // If `value` does not fit in `size` bits, we error instead of letting - // `Scalar::from_int` panic. - let truncated = truncate(value as u128, size); - if sign_extend(truncated, size) as i128 != value { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - value, - size.bits() - ) - } - + for imm in imms { + let size = imm.layout.size; allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(value, size).into(), + imm.to_scalar()?.into(), size, )?; offset += size; @@ -351,4 +335,11 @@ fn write_c_ints( Ok(()) } + + 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) + } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 2995bdc4346..3acc84dbc75 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,12 @@ +use std::time::{Duration, SystemTime}; + +use rustc::ty::layout::TyLayout; + use crate::stacked_borrows::Tag; use crate::*; -use std::time::{Duration, SystemTime}; - +// 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() @@ -14,6 +18,24 @@ fn get_time() -> (Duration, i128) { (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 @@ -45,7 +67,12 @@ fn clock_gettime( tv_nsec *= sign; } - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + 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) } @@ -78,7 +105,12 @@ fn gettimeofday( tv_usec *= sign; } - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + 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) } From 508df227e5f4820f1d600b72e626a620b2c714af Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 19:48:18 -0500 Subject: [PATCH 11/13] Group libc helper functions --- src/helpers.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 892ba7b2401..3012b1a9554 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -308,8 +308,16 @@ 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 an struct. + // different values into a struct. fn write_immediates( &mut self, ptr: &Pointer, @@ -335,11 +343,4 @@ fn write_immediates( Ok(()) } - - 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) - } } From 50618b55cd8c2cd8da905697fe80e5f3a519fb3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 16:06:37 -0500 Subject: [PATCH 12/13] Error on negative times --- src/shims/time.rs | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 3acc84dbc75..1b799b1330a 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -7,15 +7,10 @@ // 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() +fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { + SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - (duration, sign) + .map_err(|_| err_unsup_format!("Time went backwards").into()) } fn int_to_immty_checked<'tcx>( @@ -59,13 +54,9 @@ fn clock_gettime( 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 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")?)?, @@ -97,13 +88,9 @@ fn gettimeofday( 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 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")?)?, From f9c768864a7784c518b6ac1af6515950c6eff6ec Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 09:08:39 -0500 Subject: [PATCH 13/13] Use places instead of ptrs to write packed immtys --- src/helpers.rs | 18 +++++++----------- src/shims/time.rs | 12 ++++++------ tests/run-pass/clock.rs | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3012b1a9554..9107958e010 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -318,27 +318,23 @@ fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack // different values into a struct. - fn write_immediates( + fn write_packed_immediates( &mut self, - ptr: &Pointer, + place: &MPlaceTy<'tcx, 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, + for &imm in imms { + this.write_immediate_to_mplace( + *imm, + place.offset(offset, None, imm.layout, tcx)?, )?; - offset += size; + offset += imm.layout.size; } Ok(()) diff --git a/src/shims/time.rs b/src/shims/time.rs index 1b799b1330a..0153c1a912d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -10,7 +10,7 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Time went backwards").into()) + .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } fn int_to_immty_checked<'tcx>( @@ -52,7 +52,7 @@ fn clock_gettime( return Ok(-1); } - let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; + let tp = this.deref_operand(tp_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -63,11 +63,11 @@ fn clock_gettime( int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_immediates(&tp, &imms)?; + this.write_packed_immediates(&tp, &imms)?; Ok(0) } - // Foreign function used by generic unix + // Foreign function used by generic unix (in particular macOS) fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -86,7 +86,7 @@ fn gettimeofday( return Ok(-1); } - let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; + let tv = this.deref_operand(tv_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -97,7 +97,7 @@ fn gettimeofday( int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_immediates(&tv, &imms)?; + this.write_packed_immediates(&tv, &imms)?; Ok(0) } diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs index 987a78fe1f0..23f45f91ada 100644 --- a/tests/run-pass/clock.rs +++ b/tests/run-pass/clock.rs @@ -1,3 +1,4 @@ +// ignore-windows: TODO clock shims are not implemented on Windows // compile-flags: -Zmiri-disable-isolation use std::time::SystemTime;