]> git.lizzy.rs Git - rust.git/blobdiff - src/eval.rs
Fix merge conflicts
[rust.git] / src / eval.rs
index 83307c99f9c59bb7a166aebddc1a449b1a893e17..f4a8d176172d47908e0734a98c310e937a93c422 100644 (file)
@@ -3,25 +3,30 @@
 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())
-    pub seed: Option<u64>
+    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
+    pub seed: Option<u64>,
 }
 
 // Used by priroda.
@@ -33,18 +38,21 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     let mut ecx = InterpCx::new(
         tcx.at(syntax::source_map::DUMMY_SP),
         ty::ParamEnv::reveal_all(),
-        Evaluator::new(),
-        MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
+        Evaluator::new(config.communicate),
+        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 {
-        return err!(Unimplemented(
-            "miri does not support main functions without `fn()` type signatures"
-                .to_owned(),
-        ));
+        throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
     }
 
     let start_id = tcx.lang_items().start_fn().unwrap();
@@ -54,16 +62,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         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 {
-        return err!(AbiViolation(format!(
+        bug!(
             "'start' lang item should have three arguments, but has {}",
             start_mir.arg_count
-        )));
+        );
     }
 
     // Return value (in static memory so that it does not count as leak).
@@ -83,7 +92,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     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)?;
 
@@ -116,16 +127,23 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         // 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)?;
@@ -137,39 +155,40 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     }
     // 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) => {
@@ -179,7 +198,7 @@ pub fn eval_main<'tcx>(
     };
 
     // Perform the main execution.
-    let res: InterpResult = (|| {
+    let res: InterpResult<'_> = (|| {
         ecx.run()?;
         ecx.run_tls_dtors()
     })();
@@ -187,7 +206,7 @@ pub fn eval_main<'tcx>(
     // 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();
@@ -200,7 +219,7 @@ pub fn eval_main<'tcx>(
             // Special treatment for some error kinds
             let msg = match e.kind {
                 InterpError::Exit(code) => std::process::exit(code),
-                InterpError::NoMirFor(..) =>
+                err_unsup!(NoMirFor(..)) =>
                     format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
                 _ => e.to_string()
             };
@@ -220,8 +239,9 @@ pub fn eval_main<'tcx>(
                 // 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 {