X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fhelpers.rs;h=4c989db0170b5408c71116555a8fcfc0702aab17;hb=296ba8b1c84f65d123fa5b35f6f2e47e73710b08;hp=473da84aeea356c0df58737a0519ac5b53aada12;hpb=7d6aec68878ae15044ec8f075a5bede15ae421d3;p=rust.git diff --git a/src/helpers.rs b/src/helpers.rs index 473da84aeea..4c989db0170 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,7 @@ use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; +use std::time::Duration; use log::trace; @@ -58,7 +59,7 @@ fn eval_path_scalar( let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; - let const_val = this.const_eval_raw(cid)?; + let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(const_val.into())?; return Ok(const_val); } @@ -67,7 +68,7 @@ fn eval_path_scalar( fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? - .not_undef() + .check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -80,7 +81,7 @@ fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["std", "sys", "windows", module, name])? - .not_undef() + .check_init() } /// Helper function to get a `windows` constant as an `u64`. @@ -280,7 +281,7 @@ fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); - let is_unsafe_cell = match v.layout.ty.kind { + let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, @@ -376,19 +377,17 @@ fn write_packed_immediates( /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { - throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( - "`{}` not available when isolation is enabled", - name, - ))) + isolation_error(name)?; } Ok(()) } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target.target_os, + self.eval_context_ref().tcx.sess.target.os, target_os, "`{}` is only available on the `{}` target OS", name, @@ -396,18 +395,34 @@ fn assert_target_os(&self, target_os: &str, name: &str) { ) } + /// Get last error variable as a place, lazily allocating thread-local storage for it if + /// necessary. + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + if let Some(errno_place) = this.active_thread_ref().last_error { + Ok(errno_place) + } else { + // Allocate new place, set initial value to 0. + let errno_layout = this.machine.layouts.u32; + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_u32(0), errno_place.into())?; + this.active_thread_mut().last_error = Some(errno_place); + Ok(errno_place) + } + } + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable. - fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_ref(); - let errno_place = this.machine.last_error.unwrap(); - this.read_scalar(errno_place.into())?.not_undef() + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let errno_place = this.last_error_place()?; + this.read_scalar(errno_place.into())?.check_init() } /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most @@ -415,9 +430,9 @@ fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); - let target = &this.tcx.sess.target.target; - let target_os = &target.target_os; - let last_error = if target.options.target_family == Some("unix".to_owned()) { + let target = &this.tcx.sess.target; + let target_os = &target.os; + let last_error = if target.os_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", @@ -467,7 +482,7 @@ fn try_unwrap_io_result>( } } } - + fn read_scalar_at_offset( &self, op: OpTy<'tcx, Tag>, @@ -498,6 +513,35 @@ fn write_scalar_at_offset( let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; this.write_scalar(value, value_place.into()) } + + /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` + /// if the value in the `timespec` struct is invalid. Some libc functions will return + /// `EINVAL` in this case. + fn read_timespec( + &mut self, + timespec_ptr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + let tp = this.deref_operand(timespec_ptr_op)?; + let seconds_place = this.mplace_field(tp, 0)?; + let seconds_scalar = this.read_scalar(seconds_place.into())?; + let seconds = seconds_scalar.to_machine_isize(this)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; + let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; + let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; + + Ok(try { + // tv_sec must be non-negative. + let seconds: u64 = seconds.try_into().ok()?; + // tv_nsec must be non-negative. + let nanoseconds: u32 = nanoseconds.try_into().ok()?; + if nanoseconds >= 1_000_000_000 { + // tv_nsec must not be greater than 999,999,999. + None? + } + Duration::new(seconds, nanoseconds) + }) + } } /// Check that the number of args is what we expect. @@ -509,6 +553,13 @@ fn write_scalar_at_offset( throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +pub fn isolation_error(name: &str) -> InterpResult<'static> { + throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( + "{} not available when isolation is enabled", + name, + ))) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyAndLayout<'tcx>,