diff --git a/src/eval.rs b/src/eval.rs index 197cf87ba549..6f7f0ba329ce 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,5 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. +use std::ffi::OsStr; + use rand::rngs::StdRng; use rand::SeedableRng; @@ -75,26 +77,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { - // For Windows, construct a command string with all the aguments (before we take apart `config.args`). - let mut cmd = String::new(); + // Put each argument in memory, collect pointers. + let mut argvs = Vec::>::new(); for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push( - ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()), - ); + // Make space for `0` terminator. + let size = arg.len() as u64 + 1; + let arg_type = tcx.mk_array(tcx.types.u8, size); + let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); + ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?; + argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( @@ -107,7 +98,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; - // A pointer to that place is the argument. + // A pointer to that place is the 3rd argument for main. let argv = argvs_place.ptr; // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { @@ -127,6 +118,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { + // Construct a command string with all the aguments. + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); diff --git a/src/helpers.rs b/src/helpers.rs index e7da88f2bbfe..9f75c9b7fbe1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ use std::{mem, iter}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -453,9 +453,12 @@ fn try_unwrap_io_result>( /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; - Ok(bytes_to_os_str(bytes)?.into()) + fn read_os_string_from_c_string<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + where 'tcx: 'a, 'mir: 'a + { + let this = self.eval_context_ref(); + let bytes = this.memory.read_c_str(scalar)?; + bytes_to_os_str(bytes) } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what @@ -501,7 +504,7 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> } #[cfg(not(target_os = "unix"))] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) diff --git a/src/machine.rs b/src/machine.rs index edabc3bccbcc..55ac7f780fae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,8 @@ pub(crate) fn new(communicate: bool) -> Self { /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; + fn eval_context_ref<'a>(&'a self) -> &'a MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut<'a>(&'a mut self) -> &'a mut MiriEvalContext<'mir, 'tcx>; } impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { #[inline(always)]