X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fhelpers.rs;h=7f99aa1997068ae3099f0d01112423af4b71e488;hb=879000b133aed8cc1893c84eb5319b491a4756d9;hp=8a7657745b645a796f1e07a76f57c70fd594c263;hpb=aac6e2ad3e800153b6552d639e291b2b232881f4;p=rust.git diff --git a/src/helpers.rs b/src/helpers.rs index 8a7657745b6..7f99aa19970 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,10 +5,10 @@ use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; +use rustc_middle::mir; +use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -19,10 +19,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates() - .iter() - .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) - .and_then(|krate| { + tcx.crates().iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( + |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -40,7 +38,8 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -53,10 +52,7 @@ fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar( - &mut self, - path: &[&str], - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; @@ -67,9 +63,7 @@ fn eval_path_scalar( /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .check_init() + self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -101,7 +95,9 @@ fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx> /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); + let ty = this + .resolve_path(&["std", "sys", "windows", "c", name]) + .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } @@ -169,8 +165,12 @@ fn call_function( let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - if callee_abi != caller_abi { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + if this.machine.enforce_abi && callee_abi != caller_abi { + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + callee_abi.name(), + caller_abi.name() + ) } // Push frame. @@ -181,9 +181,9 @@ fn call_function( let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().ok_or_else(|| - err_ub_format!("callee has fewer arguments than expected") - )? + callee_args + .next() + .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?, )?; this.write_immediate(*arg, &callee_arg)?; } @@ -356,7 +356,11 @@ fn visit_aggregate( } } - fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + fn visit_union( + &mut self, + _v: &MPlaceTy<'tcx, Tag>, + _fields: NonZeroUsize, + ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } } @@ -465,12 +469,21 @@ fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'t })? } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. - this.eval_windows("c", match e.kind() { - NotFound => "ERROR_FILE_NOT_FOUND", - _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) - })? + this.eval_windows( + "c", + match e.kind() { + NotFound => "ERROR_FILE_NOT_FOUND", + _ => throw_unsup_format!( + "io error {} cannot be transformed into a raw os error", + e + ), + }, + )? } else { - throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os) + throw_unsup_format!( + "setting the last OS error from an io::Error is unsupported for {}.", + target_os + ) }; this.set_last_error(last_error) } @@ -553,26 +566,89 @@ fn read_timespec( Duration::new(seconds, nanoseconds) }) } + + fn read_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a [u8]> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let size1 = Size::from_bytes(1); + let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. + + // Step 1: determine the length. + let mut len = Size::ZERO; + loop { + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; + if byte == 0 { + break; + } else { + len = len + size1; + } + } + + // Step 2: get the bytes. + this.memory.read_bytes(ptr.into(), len) + } + + fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_ref(); + let size2 = Size::from_bytes(2); + let align2 = Align::from_bytes(2).unwrap(); + + let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. + let mut wchars = Vec::new(); + loop { + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; + if wchar == 0 { + break; + } else { + wchars.push(wchar); + ptr = ptr.offset(size2, this)?; + } + } + + Ok(wchars) + } + + /// Check that the ABI is what we expect. + fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { + if self.eval_context_ref().machine.enforce_abi && abi != exp_abi { + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + exp_abi.name(), + abi.name() + ) + } + Ok(()) + } + + fn in_std(&self) -> bool { + let this = self.eval_context_ref(); + this.tcx.def_path(this.frame().instance.def_id()).krate + == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate + } } /// Check that the number of args is what we expect. -pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> - where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> { +pub fn check_arg_count<'a, 'tcx, const N: usize>( + args: &'a [OpTy<'tcx, Tag>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> +where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, +{ if let Ok(ops) = args.try_into() { return Ok(ops); } throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Check that the ABI is what we expect. -pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { - if abi == exp_abi { - Ok(()) - } else { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name()) - } -} - pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled",