diff --git a/src/machine.rs b/src/machine.rs index f8c7168a58..494afa407a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -78,15 +78,21 @@ pub struct MemoryExtra { /// Whether to enforce the validity invariant. pub(crate) validate: bool, + /// Contains the `environ` static. + pub(crate) environ: Option>, } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option) -> Self { + pub fn new( + rng: StdRng, validate: bool, + tracked_pointer_tag: Option, + ) -> Self { MemoryExtra { stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))), intptrcast: Default::default(), rng: RefCell::new(rng), validate, + environ: None, } } } @@ -266,7 +272,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( tcx: TyCtxt<'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + id: AllocId, + memory_extra: &MemoryExtra, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), @@ -278,11 +286,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) + // We got tcx memory. Let the machine initialize its "extra" stuff. + let (alloc, tag) = Self::init_allocation_extra( + memory_extra, + id, // always use the ID we got as input, not the "hidden" one. + Cow::Owned(Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi)), + Self::STATIC_KIND.map(MemoryKind::Machine), + ); + debug_assert_eq!(tag, Self::tag_static_base_pointer(memory_extra, id)); + alloc + } + "environ" => { + Cow::Owned(memory_extra.environ.as_ref().cloned().unwrap()) } _ => throw_unsup_format!("can't access foreign static: {}", link_name), }; - Ok(Cow::Owned(alloc)) + Ok(alloc) } #[inline(always)] diff --git a/src/shims/env.rs b/src/shims/env.rs index 9617401044..6e9ee7b242 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -3,6 +3,7 @@ use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; +use crate::rustc_target::abi::LayoutOf; use crate::*; use rustc::ty::layout::Size; @@ -20,15 +21,34 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) { + let mut vars = Vec::new(); if ecx.machine.communicate { + // Put each environment variable pointer in `EnvVars`, collect pointers. for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); + vars.push(var_ptr.into()); } } } + // add trailing null pointer + vars.push(Scalar::from_int(0, ecx.pointer_size())); + // Make an array with all these pointers, in the Miri memory. + let tcx = ecx.tcx; + let environ_layout = + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), vars.len() as u64)).unwrap(); + let environ_place = ecx.allocate(environ_layout, MiriMemoryKind::Env.into()); + for (idx, var) in vars.into_iter().enumerate() { + let place = ecx.mplace_field(environ_place, idx as u64).unwrap(); + ecx.write_scalar(var, place.into()).unwrap(); + } + ecx.memory.mark_immutable(environ_place.ptr.assert_ptr().alloc_id).unwrap(); + // A pointer to that place corresponds to the `environ` static. + let environ_ptr = ecx.force_ptr(environ_place.ptr).unwrap(); + let environ_alloc = ecx.memory.get_raw(environ_ptr.alloc_id).unwrap().clone(); + ecx.memory.extra.environ = Some(environ_alloc); } }