use rand::rngs::StdRng;
use rand::SeedableRng;
-use syntax::source_map::DUMMY_SP;
-use rustc::ty::{self, TyCtxt};
-use rustc::ty::layout::{LayoutOf, Size, Align};
use rustc::hir::def_id::DefId;
+use rustc::ty::layout::{Align, LayoutOf, Size};
+use rustc::ty::{self, TyCtxt};
+use syntax::source_map::DUMMY_SP;
use crate::{
- InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error,
- Scalar, Tag, Pointer, FnVal,
- MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt,
+ struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError,
+ InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag,
+ TlsEvalContextExt,
};
/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
+ /// Determine if validity checking and Stacked Borrows are enabled.
pub validate: bool,
/// Determines if communication with the host environment is enabled.
pub communicate: bool,
+ /// Environment variables that should always be isolated from the host.
+ pub excluded_env_vars: Vec<String>,
+ /// Command-line arguments passed to the interpreted program.
pub args: Vec<String>,
-
- /// The seed to use when non-determinism is required (e.g. getrandom())
+ /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
pub seed: Option<u64>,
}
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(config.communicate),
- MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
+ MemoryExtra::new(
+ StdRng::seed_from_u64(config.seed.unwrap_or(0)),
+ config.validate,
+ ),
);
+ // Complete initialization.
+ EnvVars::init(&mut ecx, config.excluded_env_vars);
+ // Setup first stack-frame
let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
- let main_mir = ecx.load_mir(main_instance.def)?;
+ let main_mir = ecx.load_mir(main_instance.def, None)?;
if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
- throw_unsup_format!(
- "miri does not support main functions without `fn()` type signatures"
- );
+ throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
}
let start_id = tcx.lang_items().start_fn().unwrap();
ecx.tcx.tcx,
ty::ParamEnv::reveal_all(),
start_id,
- ecx.tcx.mk_substs(
- ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))
- ).unwrap();
- let start_mir = ecx.load_mir(start_instance.def)?;
+ ecx.tcx
+ .mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
+ )
+ .unwrap();
+ let start_mir = ecx.load_mir(start_instance.def, None)?;
if start_mir.arg_count != 3 {
bug!(
let mut args = ecx.frame().body.args_iter();
// First argument: pointer to `main()`.
- let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance));
+ let main_ptr = ecx
+ .memory
+ .create_fn_alloc(FnVal::Instance(main_instance));
let dest = ecx.local_place(args.next().unwrap())?;
ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
// Add `0` terminator.
let mut arg = arg.into_bytes();
arg.push(0);
- argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()));
+ argvs.push(
+ ecx.memory
+ .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()),
+ );
}
// Make an array with all these pointers, in the Miri memory.
- let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?;
+ let argvs_layout = ecx.layout_of(
+ ecx.tcx
+ .mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64),
+ )?;
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
for (idx, arg) in argvs.into_iter().enumerate() {
let place = ecx.mplace_field(argvs_place, idx as u64)?;
ecx.write_scalar(Scalar::Ptr(arg), place.into())?;
}
- ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
+ ecx.memory
+ .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
// Write a pointer to that place as the argument.
let argv = argvs_place.ptr;
ecx.write_scalar(argv, dest)?;
}
// Store command line as UTF-16 for Windows `GetCommandLineW`.
{
- let tcx = &{ecx.tcx.tcx};
let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
- let cmd_ptr = ecx.memory_mut().allocate(
+ let cmd_ptr = ecx.memory.allocate(
Size::from_bytes(cmd_utf16.len() as u64 * 2),
Align::from_bytes(2).unwrap(),
MiriMemoryKind::Env.into(),
);
ecx.machine.cmd_line = Some(cmd_ptr);
- // Store the UTF-16 string.
+ // Store the UTF-16 string. We just allocated so we know the bounds are fine.
let char_size = Size::from_bytes(2);
- let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
+ let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?;
let mut cur_ptr = cmd_ptr;
for &c in cmd_utf16.iter() {
cmd_alloc.write_scalar(
- tcx,
+ &*ecx.tcx,
cur_ptr,
Scalar::from_uint(c, char_size).into(),
char_size,
)?;
- cur_ptr = cur_ptr.offset(char_size, tcx)?;
+ cur_ptr = cur_ptr.offset(char_size, &*ecx.tcx)?;
}
}
- assert!(args.next().is_none(), "start lang item has more arguments than expected");
+ args.next().expect_none("start lang item has more arguments than expected");
+
+ // Set the last_error to 0
+ let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?;
+ let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into());
+ ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
+ ecx.machine.last_error = Some(errno_place);
Ok(ecx)
}
-pub fn eval_main<'tcx>(
- tcx: TyCtxt<'tcx>,
- main_id: DefId,
- config: MiriConfig,
-) {
+pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) {
let mut ecx = match create_ecx(tcx, main_id, config) {
Ok(ecx) => ecx,
Err(mut err) => {
// Process the result.
match res {
Ok(()) => {
- let leaks = ecx.memory().leak_report();
+ let leaks = ecx.memory.leak_report();
// Disable the leak test on some platforms where we do not
// correctly implement TLS destructors.
let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
// We iterate with indices because we need to look at the next frame (the caller).
for idx in 0..frames.len() {
let frame_info = &frames[idx];
- let call_site_is_local = frames.get(idx+1).map_or(false,
- |caller_info| caller_info.instance.def_id().is_local());
+ let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
+ caller_info.instance.def_id().is_local()
+ });
if call_site_is_local {
err.span_note(frame_info.call_site, &frame_info.to_string());
} else {