]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #802 - RalfJung:machine, r=RalfJung
authorbors <bors@rust-lang.org>
Sat, 29 Jun 2019 11:52:02 +0000 (11:52 +0000)
committerbors <bors@rust-lang.org>
Sat, 29 Jun 2019 11:52:02 +0000 (11:52 +0000)
some lib.rs refactoring

Taken out of https://github.com/rust-lang/miri/pull/799 so that we can land it now and resolve merge conflicts instead of dragging them along.

Splits lib.rs into machine.rs for the machine state and trait impl, and eval.rs for the main evaluator loop and setting up the initial stack frame.

src/eval.rs [new file with mode: 0644]
src/helpers.rs
src/lib.rs
src/machine.rs [new file with mode: 0644]
src/memory.rs [deleted file]
src/operator.rs

diff --git a/src/eval.rs b/src/eval.rs
new file mode 100644 (file)
index 0000000..5f7d85b
--- /dev/null
@@ -0,0 +1,248 @@
+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::mir;
+
+use crate::{
+    InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error,
+    Scalar, Tag, Pointer,
+    MiriMemoryKind, Evaluator, TlsEvalContextExt,
+};
+
+/// Configuration needed to spawn a Miri instance.
+#[derive(Clone)]
+pub struct MiriConfig {
+    pub validate: bool,
+    pub args: Vec<String>,
+
+    // The seed to use when non-determinism is required (e.g. getrandom())
+    pub seed: Option<u64>
+}
+
+// Used by priroda.
+pub fn create_ecx<'mir, 'tcx: 'mir>(
+    tcx: TyCtxt<'tcx>,
+    main_id: DefId,
+    config: MiriConfig,
+) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> {
+    let mut ecx = InterpretCx::new(
+        tcx.at(syntax::source_map::DUMMY_SP),
+        ty::ParamEnv::reveal_all(),
+        Evaluator::new(config.validate),
+    );
+
+    // FIXME: InterpretCx::new should take an initial MemoryExtra
+    ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64);
+    
+    let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
+    let main_mir = ecx.load_mir(main_instance.def)?;
+
+    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(),
+        ));
+    }
+
+    let start_id = tcx.lang_items().start_fn().unwrap();
+    let main_ret_ty = tcx.fn_sig(main_id).output();
+    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
+    let start_instance = ty::Instance::resolve(
+        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)?;
+
+    if start_mir.arg_count != 3 {
+        return err!(AbiViolation(format!(
+            "'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).
+    let ret = ecx.layout_of(start_mir.return_ty())?;
+    let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into());
+
+    // Push our stack frame.
+    ecx.push_stack_frame(
+        start_instance,
+        // There is no call site.
+        DUMMY_SP,
+        start_mir,
+        Some(ret_ptr.into()),
+        StackPopCleanup::None { cleanup: true },
+    )?;
+
+    let mut args = ecx.frame().body.args_iter();
+
+    // First argument: pointer to `main()`.
+    let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
+    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
+    ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
+
+    // Second argument (argc): `1`.
+    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
+    let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size);
+    ecx.write_scalar(argc, dest)?;
+    // Store argc for macOS's `_NSGetArgc`.
+    {
+        let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into());
+        ecx.write_scalar(argc, argc_place.into())?;
+        ecx.machine.argc = Some(argc_place.ptr.to_ptr()?);
+    }
+
+    // FIXME: extract main source file path.
+    // Third argument (`argv`): created from `config.args`.
+    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
+    // For Windows, 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());
+    // Collect the pointers to the individual strings.
+    let mut argvs = Vec::<Pointer<Tag>>::new();
+    for arg in config.args {
+        // 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()));
+    }
+    // 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_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.to_ptr()?.alloc_id)?;
+    // Write a pointer to that place as the argument.
+    let argv = argvs_place.ptr;
+    ecx.write_scalar(argv, dest)?;
+    // Store `argv` for macOS `_NSGetArgv`.
+    {
+        let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into());
+        ecx.write_scalar(argv, argv_place.into())?;
+        ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
+    }
+    // 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(
+            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.
+        let char_size = Size::from_bytes(2);
+        let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
+        let mut cur_ptr = cmd_ptr;
+        for &c in cmd_utf16.iter() {
+            cmd_alloc.write_scalar(
+                tcx,
+                cur_ptr,
+                Scalar::from_uint(c, char_size).into(),
+                char_size,
+            )?;
+            cur_ptr = cur_ptr.offset(char_size, tcx)?;
+        }
+    }
+    assert!(args.next().is_none(), "start lang item has more arguments than expected");
+
+    Ok(ecx)
+}
+
+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) => {
+            err.print_backtrace();
+            panic!("Miri initialziation error: {}", err.kind)
+        }
+    };
+
+    // Perform the main execution.
+    let res: InterpResult = (|| {
+        ecx.run()?;
+        ecx.run_tls_dtors()
+    })();
+
+    // Process the result.
+    match res {
+        Ok(()) => {
+            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();
+            let ignore_leaks = target_os == "windows" || target_os == "macos";
+            if !ignore_leaks && leaks != 0 {
+                tcx.sess.err("the evaluated program leaked memory");
+            }
+        }
+        Err(mut e) => {
+            // Special treatment for some error kinds
+            let msg = match e.kind {
+                InterpError::Exit(code) => std::process::exit(code),
+                InterpError::NoMirFor(..) =>
+                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
+                _ => e.to_string()
+            };
+            e.print_backtrace();
+            if let Some(frame) = ecx.stack().last() {
+                let block = &frame.body.basic_blocks()[frame.block];
+                let span = if frame.stmt < block.statements.len() {
+                    block.statements[frame.stmt].source_info.span
+                } else {
+                    block.terminator().source_info.span
+                };
+
+                let msg = format!("Miri evaluation error: {}", msg);
+                let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str());
+                let frames = ecx.generate_stacktrace(None);
+                err.span_label(span, msg);
+                // 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());
+                    if call_site_is_local {
+                        err.span_note(frame_info.call_site, &frame_info.to_string());
+                    } else {
+                        err.note(&frame_info.to_string());
+                    }
+                }
+                err.emit();
+            } else {
+                ecx.tcx.sess.err(&msg);
+            }
+
+            for (i, frame) in ecx.stack().iter().enumerate() {
+                trace!("-------------------");
+                trace!("Frame {}", i);
+                trace!("    return: {:?}", frame.return_place.map(|p| *p));
+                for (i, local) in frame.locals.iter().enumerate() {
+                    trace!("    local {}: {:?}", i, local.value);
+                }
+            }
+        }
+    }
+}
index 62a546767e8952ac0005c92b38660625eabcffe1..f65eef557c967260fafc1c0b7dc6d6ca0425a7e8 100644 (file)
@@ -1,6 +1,6 @@
 use std::mem;
 
-use rustc::ty::{self, layout};
+use rustc::ty::{self, layout::{self, Size}};
 use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
 
 use crate::*;
index 6b1ada69d3975dfc38e9e8e8e6acd833a1699f55..ab9e9854c34cbd84ea27ccd14ebce84f47945557 100644 (file)
 mod mono_hash_map;
 mod stacked_borrows;
 mod intptrcast;
-mod memory;
+mod machine;
+mod eval;
 
-use std::collections::HashMap;
-use std::borrow::Cow;
-use std::rc::Rc;
-
-use rand::rngs::StdRng;
-use rand::SeedableRng;
-
-use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
-use rustc::ty::layout::{LayoutOf, Size, Align};
-use rustc::hir::def_id::DefId;
-use rustc::mir;
+// Make all those symbols available in the same place as our own.
 pub use rustc_mir::interpret::*;
 // Resolve ambiguity.
 pub use rustc_mir::interpret::{self, AllocMap, PlaceTy};
-use syntax::attr;
-use syntax::source_map::DUMMY_SP;
-use syntax::symbol::sym;
 
 pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt;
 pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
 pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt;
 pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
-use crate::range_map::RangeMap;
-#[allow(unused_imports)] // FIXME: rustc bug, issue <https://github.com/rust-lang/rust/issues/53682>.
+pub use crate::range_map::RangeMap;
 pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt};
-use crate::mono_hash_map::MonoHashMap;
-pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt};
-use crate::memory::AllocExtra;
-
-// Used by priroda.
-pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item};
+pub use crate::mono_hash_map::MonoHashMap;
+pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item};
+pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt};
+pub use crate::eval::{eval_main, create_ecx, MiriConfig};
 
 /// Insert rustc arguments at the beginning of the argument list that Miri wants to be
 /// set per default, for maximal validation power.
@@ -62,550 +47,3 @@ pub fn miri_default_args() -> &'static [&'static str] {
     // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources.
     &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"]
 }
-
-/// Configuration needed to spawn a Miri instance.
-#[derive(Clone)]
-pub struct MiriConfig {
-    pub validate: bool,
-    pub args: Vec<String>,
-
-    // The seed to use when non-determinism is required (e.g. getrandom())
-    pub seed: Option<u64>
-}
-
-// Used by priroda.
-pub fn create_ecx<'mir, 'tcx: 'mir>(
-    tcx: TyCtxt<'tcx>,
-    main_id: DefId,
-    config: MiriConfig,
-) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> {
-    let mut ecx = InterpretCx::new(
-        tcx.at(syntax::source_map::DUMMY_SP),
-        ty::ParamEnv::reveal_all(),
-        Evaluator::new(config.validate),
-    );
-
-    // FIXME: InterpretCx::new should take an initial MemoryExtra
-    ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64);
-    
-    let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
-    let main_mir = ecx.load_mir(main_instance.def)?;
-
-    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(),
-        ));
-    }
-
-    let start_id = tcx.lang_items().start_fn().unwrap();
-    let main_ret_ty = tcx.fn_sig(main_id).output();
-    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
-    let start_instance = ty::Instance::resolve(
-        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)?;
-
-    if start_mir.arg_count != 3 {
-        return err!(AbiViolation(format!(
-            "'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).
-    let ret = ecx.layout_of(start_mir.return_ty())?;
-    let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into());
-
-    // Push our stack frame.
-    ecx.push_stack_frame(
-        start_instance,
-        // There is no call site.
-        DUMMY_SP,
-        start_mir,
-        Some(ret_ptr.into()),
-        StackPopCleanup::None { cleanup: true },
-    )?;
-
-    let mut args = ecx.frame().body.args_iter();
-
-    // First argument: pointer to `main()`.
-    let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
-    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
-    ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
-
-    // Second argument (argc): `1`.
-    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
-    let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size);
-    ecx.write_scalar(argc, dest)?;
-    // Store argc for macOS's `_NSGetArgc`.
-    {
-        let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into());
-        ecx.write_scalar(argc, argc_place.into())?;
-        ecx.machine.argc = Some(argc_place.ptr.to_ptr()?);
-    }
-
-    // FIXME: extract main source file path.
-    // Third argument (`argv`): created from `config.args`.
-    let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
-    // For Windows, 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());
-    // Collect the pointers to the individual strings.
-    let mut argvs = Vec::<Pointer<Tag>>::new();
-    for arg in config.args {
-        // 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()));
-    }
-    // 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_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.to_ptr()?.alloc_id)?;
-    // Write a pointer to that place as the argument.
-    let argv = argvs_place.ptr;
-    ecx.write_scalar(argv, dest)?;
-    // Store `argv` for macOS `_NSGetArgv`.
-    {
-        let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into());
-        ecx.write_scalar(argv, argv_place.into())?;
-        ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
-    }
-    // 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(
-            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.
-        let char_size = Size::from_bytes(2);
-        let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
-        let mut cur_ptr = cmd_ptr;
-        for &c in cmd_utf16.iter() {
-            cmd_alloc.write_scalar(
-                tcx,
-                cur_ptr,
-                Scalar::from_uint(c, char_size).into(),
-                char_size,
-            )?;
-            cur_ptr = cur_ptr.offset(char_size, tcx)?;
-        }
-    }
-    assert!(args.next().is_none(), "start lang item has more arguments than expected");
-
-    Ok(ecx)
-}
-
-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) => {
-            err.print_backtrace();
-            panic!("Miri initialziation error: {}", err.kind)
-        }
-    };
-
-    // Perform the main execution.
-    let res: InterpResult = (|| {
-        ecx.run()?;
-        ecx.run_tls_dtors()
-    })();
-
-    // Process the result.
-    match res {
-        Ok(()) => {
-            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();
-            let ignore_leaks = target_os == "windows" || target_os == "macos";
-            if !ignore_leaks && leaks != 0 {
-                tcx.sess.err("the evaluated program leaked memory");
-            }
-        }
-        Err(mut e) => {
-            // Special treatment for some error kinds
-            let msg = match e.kind {
-                InterpError::Exit(code) => std::process::exit(code),
-                InterpError::NoMirFor(..) =>
-                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
-                _ => e.to_string()
-            };
-            e.print_backtrace();
-            if let Some(frame) = ecx.stack().last() {
-                let block = &frame.body.basic_blocks()[frame.block];
-                let span = if frame.stmt < block.statements.len() {
-                    block.statements[frame.stmt].source_info.span
-                } else {
-                    block.terminator().source_info.span
-                };
-
-                let msg = format!("Miri evaluation error: {}", msg);
-                let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str());
-                let frames = ecx.generate_stacktrace(None);
-                err.span_label(span, msg);
-                // 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());
-                    if call_site_is_local {
-                        err.span_note(frame_info.call_site, &frame_info.to_string());
-                    } else {
-                        err.note(&frame_info.to_string());
-                    }
-                }
-                err.emit();
-            } else {
-                ecx.tcx.sess.err(&msg);
-            }
-
-            for (i, frame) in ecx.stack().iter().enumerate() {
-                trace!("-------------------");
-                trace!("Frame {}", i);
-                trace!("    return: {:?}", frame.return_place.map(|p| *p));
-                for (i, local) in frame.locals.iter().enumerate() {
-                    trace!("    local {}: {:?}", i, local.value);
-                }
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum MiriMemoryKind {
-    /// `__rust_alloc` memory.
-    Rust,
-    /// `malloc` memory.
-    C,
-    /// Part of env var emulation.
-    Env,
-    /// Statics.
-    Static,
-}
-
-impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
-    #[inline(always)]
-    fn into(self) -> MemoryKind<MiriMemoryKind> {
-        MemoryKind::Machine(self)
-    }
-}
-
-impl MayLeak for MiriMemoryKind {
-    #[inline(always)]
-    fn may_leak(self) -> bool {
-        use self::MiriMemoryKind::*;
-        match self {
-            Rust | C => false,
-            Env | Static => true,
-        }
-    }
-}
-
-pub struct Evaluator<'tcx> {
-    /// Environment variables set by `setenv`.
-    /// Miri does not expose env vars from the host to the emulated program.
-    pub(crate) env_vars: HashMap<Vec<u8>, Pointer<Tag>>,
-
-    /// Program arguments (`Option` because we can only initialize them after creating the ecx).
-    /// These are *pointers* to argc/argv because macOS.
-    /// We also need the full command line as one string because of Windows.
-    pub(crate) argc: Option<Pointer<Tag>>,
-    pub(crate) argv: Option<Pointer<Tag>>,
-    pub(crate) cmd_line: Option<Pointer<Tag>>,
-
-    /// Last OS error.
-    pub(crate) last_error: u32,
-
-    /// TLS state.
-    pub(crate) tls: TlsData<'tcx>,
-
-    /// Whether to enforce the validity invariant.
-    pub(crate) validate: bool,
-}
-
-impl<'tcx> Evaluator<'tcx> {
-    fn new(validate: bool) -> Self {
-        Evaluator {
-            env_vars: HashMap::default(),
-            argc: None,
-            argv: None,
-            cmd_line: None,
-            last_error: 0,
-            tls: TlsData::default(),
-            validate,
-        }
-    }
-}
-
-// FIXME: rustc issue <https://github.com/rust-lang/rust/issues/47131>.
-#[allow(dead_code)]
-type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>;
-
-// 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>;
-}
-impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {
-    #[inline(always)]
-    fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> {
-        self
-    }
-    #[inline(always)]
-    fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> {
-        self
-    }
-}
-
-impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
-    type MemoryKinds = MiriMemoryKind;
-
-    type FrameExtra = stacked_borrows::CallId;
-    type MemoryExtra = memory::MemoryExtra;
-    type AllocExtra = memory::AllocExtra;
-    type PointerTag = Tag;
-
-    type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
-
-    const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Static);
-
-    #[inline(always)]
-    fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool {
-        ecx.machine.validate
-    }
-
-    /// Returns `Ok()` when the function was handled; fail otherwise.
-    #[inline(always)]
-    fn find_fn(
-        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
-        instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx, Tag>],
-        dest: Option<PlaceTy<'tcx, Tag>>,
-        ret: Option<mir::BasicBlock>,
-    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
-        ecx.find_fn(instance, args, dest, ret)
-    }
-
-    #[inline(always)]
-    fn call_intrinsic(
-        ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>,
-        instance: ty::Instance<'tcx>,
-        args: &[OpTy<'tcx, Tag>],
-        dest: PlaceTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx> {
-        ecx.call_intrinsic(instance, args, dest)
-    }
-
-    #[inline(always)]
-    fn ptr_op(
-        ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>,
-        bin_op: mir::BinOp,
-        left: ImmTy<'tcx, Tag>,
-        right: ImmTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)> {
-        ecx.ptr_op(bin_op, left, right)
-    }
-
-    fn box_alloc(
-        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
-        dest: PlaceTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx> {
-        trace!("box_alloc for {:?}", dest.layout.ty);
-        // Call the `exchange_malloc` lang item.
-        let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
-        let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
-        let malloc_mir = ecx.load_mir(malloc.def)?;
-        ecx.push_stack_frame(
-            malloc,
-            malloc_mir.span,
-            malloc_mir,
-            Some(dest),
-            // Don't do anything when we are done. The `statement()` function will increment
-            // the old stack frame's stmt counter to the next statement, which means that when
-            // `exchange_malloc` returns, we go on evaluating exactly where we want to be.
-            StackPopCleanup::None { cleanup: true },
-        )?;
-
-        let mut args = ecx.frame().body.args_iter();
-        let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?;
-
-        // First argument: `size`.
-        // (`0` is allowed here -- this is expected to be handled by the lang item).
-        let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
-        let size = layout.size.bytes();
-        ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?;
-
-        // Second argument: `align`.
-        let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
-        let align = layout.align.abi.bytes();
-        ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?;
-
-        // No more arguments.
-        assert!(
-            args.next().is_none(),
-            "`exchange_malloc` lang item has more arguments than expected"
-        );
-        Ok(())
-    }
-
-    fn find_foreign_static(
-        def_id: DefId,
-        tcx: TyCtxtAt<'tcx>,
-    ) -> 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(),
-            None => tcx.item_name(def_id).as_str(),
-        };
-
-        let alloc = match link_name.get() {
-            "__cxa_thread_atexit_impl" => {
-                // 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)
-            }
-            _ => return err!(Unimplemented(
-                    format!("can't access foreign static: {}", link_name),
-                )),
-        };
-        Ok(Cow::Owned(alloc))
-    }
-
-    #[inline(always)]
-    fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
-    {
-        // We are not interested in detecting loops.
-        Ok(())
-    }
-
-    fn tag_allocation<'b>(
-        id: AllocId,
-        alloc: Cow<'b, Allocation>,
-        kind: Option<MemoryKind<Self::MemoryKinds>>,
-        memory: &Memory<'mir, 'tcx, Self>,
-    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
-        let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
-        let alloc = alloc.into_owned();
-        let (stacks, base_tag) = Stacks::new_allocation(
-            id,
-            Size::from_bytes(alloc.bytes.len() as u64),
-            Rc::clone(&memory.extra.stacked_borrows),
-            kind,
-        );
-        if kind != MiriMemoryKind::Static.into() {
-            assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers");
-            // Now we can rely on the inner pointers being static, too.
-        }
-        let mut memory_extra = memory.extra.stacked_borrows.borrow_mut();
-        let alloc: Allocation<Tag, Self::AllocExtra> = Allocation {
-            bytes: alloc.bytes,
-            relocations: Relocations::from_presorted(
-                alloc.relocations.iter()
-                    // The allocations in the relocations (pointers stored *inside* this allocation)
-                    // all get the base pointer tag.
-                    .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc)))
-                    .collect()
-            ),
-            undef_mask: alloc.undef_mask,
-            align: alloc.align,
-            mutability: alloc.mutability,
-            extra: AllocExtra {
-                stacked_borrows: stacks,
-                intptrcast: Default::default(),
-            },
-        };
-        (Cow::Owned(alloc), base_tag)
-    }
-
-    #[inline(always)]
-    fn tag_static_base_pointer(
-        id: AllocId,
-        memory: &Memory<'mir, 'tcx, Self>,
-    ) -> Self::PointerTag {
-        memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id)
-    }
-
-    #[inline(always)]
-    fn retag(
-        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
-        kind: mir::RetagKind,
-        place: PlaceTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx> {
-        if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) {
-            // No tracking, or no retagging. The latter is possible because a dependency of ours
-            // might be called with different flags than we are, so there are `Retag`
-            // statements but we do not want to execute them.
-            // Also, honor the whitelist in `enforce_validity` because otherwise we might retag
-            // uninitialized data.
-             Ok(())
-        } else {
-            ecx.retag(kind, place)
-        }
-    }
-
-    #[inline(always)]
-    fn stack_push(
-        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
-    ) -> InterpResult<'tcx, stacked_borrows::CallId> {
-        Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call())
-    }
-
-    #[inline(always)]
-    fn stack_pop(
-        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
-        extra: stacked_borrows::CallId,
-    ) -> InterpResult<'tcx> {
-        Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra))
-    }
-
-    fn int_to_ptr(
-        int: u64,
-        memory: &Memory<'mir, 'tcx, Self>,
-    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
-        if int == 0 {
-            err!(InvalidNullPointerUsage)
-        } else if memory.extra.rng.is_none() {
-            err!(ReadBytesAsPointer)
-        } else {
-           intptrcast::GlobalState::int_to_ptr(int, memory)
-        }
-    }
-    fn ptr_to_int(
-        ptr: Pointer<Self::PointerTag>,
-        memory: &Memory<'mir, 'tcx, Self>,
-    ) -> InterpResult<'tcx, u64> {
-        if memory.extra.rng.is_none() {
-            err!(ReadPointerAsBytes)
-        } else {
-            intptrcast::GlobalState::ptr_to_int(ptr, memory)
-        }
-    }
-}
diff --git a/src/machine.rs b/src/machine.rs
new file mode 100644 (file)
index 0000000..eb177fa
--- /dev/null
@@ -0,0 +1,384 @@
+use std::rc::Rc;
+use std::borrow::Cow;
+use std::collections::HashMap;
+
+use rand::rngs::StdRng;
+
+use syntax::attr;
+use syntax::symbol::sym;
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt};
+use rustc::mir;
+
+use crate::*;
+
+/// Extra memory kinds
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum MiriMemoryKind {
+    /// `__rust_alloc` memory.
+    Rust,
+    /// `malloc` memory.
+    C,
+    /// Part of env var emulation.
+    Env,
+    /// Statics.
+    Static,
+}
+
+impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
+    #[inline(always)]
+    fn into(self) -> MemoryKind<MiriMemoryKind> {
+        MemoryKind::Machine(self)
+    }
+}
+
+/// Extra per-allocation data
+#[derive(Debug, Clone)]
+pub struct AllocExtra {
+    pub stacked_borrows: stacked_borrows::AllocExtra,
+    pub intptrcast: intptrcast::AllocExtra,
+}
+
+/// Extra global memory data
+#[derive(Default, Clone, Debug)]
+pub struct MemoryExtra {
+    pub stacked_borrows: stacked_borrows::MemoryExtra,
+    pub intptrcast: intptrcast::MemoryExtra,
+    /// The random number generator to use if Miri is running in non-deterministic mode and to
+    /// enable intptrcast
+    pub(crate) rng: Option<StdRng>
+}
+
+impl MemoryExtra {
+    pub fn with_rng(rng: Option<StdRng>) -> Self {
+        MemoryExtra {
+            stacked_borrows: Default::default(),
+            intptrcast: Default::default(),
+            rng,
+        }
+    }
+}
+
+/// The machine itself.
+pub struct Evaluator<'tcx> {
+    /// Environment variables set by `setenv`.
+    /// Miri does not expose env vars from the host to the emulated program.
+    pub(crate) env_vars: HashMap<Vec<u8>, Pointer<Tag>>,
+
+    /// Program arguments (`Option` because we can only initialize them after creating the ecx).
+    /// These are *pointers* to argc/argv because macOS.
+    /// We also need the full command line as one string because of Windows.
+    pub(crate) argc: Option<Pointer<Tag>>,
+    pub(crate) argv: Option<Pointer<Tag>>,
+    pub(crate) cmd_line: Option<Pointer<Tag>>,
+
+    /// Last OS error.
+    pub(crate) last_error: u32,
+
+    /// TLS state.
+    pub(crate) tls: TlsData<'tcx>,
+
+    /// Whether to enforce the validity invariant.
+    pub(crate) validate: bool,
+}
+
+impl<'tcx> Evaluator<'tcx> {
+    pub(crate) fn new(validate: bool) -> Self {
+        Evaluator {
+            env_vars: HashMap::default(),
+            argc: None,
+            argv: None,
+            cmd_line: None,
+            last_error: 0,
+            tls: TlsData::default(),
+            validate,
+        }
+    }
+}
+
+/// A rustc InterpretCx for Miri.
+pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>;
+
+/// 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>;
+}
+impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {
+    #[inline(always)]
+    fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> {
+        self
+    }
+    #[inline(always)]
+    fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> {
+        self
+    }
+}
+
+/// Machine hook implementations.
+impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
+    type MemoryKinds = MiriMemoryKind;
+
+    type FrameExtra = stacked_borrows::CallId;
+    type MemoryExtra = MemoryExtra;
+    type AllocExtra = AllocExtra;
+    type PointerTag = Tag;
+
+    type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
+
+    const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Static);
+
+    #[inline(always)]
+    fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool {
+        ecx.machine.validate
+    }
+
+    /// Returns `Ok()` when the function was handled; fail otherwise.
+    #[inline(always)]
+    fn find_fn(
+        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
+        instance: ty::Instance<'tcx>,
+        args: &[OpTy<'tcx, Tag>],
+        dest: Option<PlaceTy<'tcx, Tag>>,
+        ret: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
+        ecx.find_fn(instance, args, dest, ret)
+    }
+
+    #[inline(always)]
+    fn call_intrinsic(
+        ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>,
+        instance: ty::Instance<'tcx>,
+        args: &[OpTy<'tcx, Tag>],
+        dest: PlaceTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx> {
+        ecx.call_intrinsic(instance, args, dest)
+    }
+
+    #[inline(always)]
+    fn ptr_op(
+        ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>,
+        bin_op: mir::BinOp,
+        left: ImmTy<'tcx, Tag>,
+        right: ImmTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx, (Scalar<Tag>, bool)> {
+        ecx.ptr_op(bin_op, left, right)
+    }
+
+    fn box_alloc(
+        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
+        dest: PlaceTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx> {
+        trace!("box_alloc for {:?}", dest.layout.ty);
+        // Call the `exchange_malloc` lang item.
+        let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
+        let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
+        let malloc_mir = ecx.load_mir(malloc.def)?;
+        ecx.push_stack_frame(
+            malloc,
+            malloc_mir.span,
+            malloc_mir,
+            Some(dest),
+            // Don't do anything when we are done. The `statement()` function will increment
+            // the old stack frame's stmt counter to the next statement, which means that when
+            // `exchange_malloc` returns, we go on evaluating exactly where we want to be.
+            StackPopCleanup::None { cleanup: true },
+        )?;
+
+        let mut args = ecx.frame().body.args_iter();
+        let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?;
+
+        // First argument: `size`.
+        // (`0` is allowed here -- this is expected to be handled by the lang item).
+        let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
+        let size = layout.size.bytes();
+        ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?;
+
+        // Second argument: `align`.
+        let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
+        let align = layout.align.abi.bytes();
+        ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?;
+
+        // No more arguments.
+        assert!(
+            args.next().is_none(),
+            "`exchange_malloc` lang item has more arguments than expected"
+        );
+        Ok(())
+    }
+
+    fn find_foreign_static(
+        def_id: DefId,
+        tcx: TyCtxtAt<'tcx>,
+    ) -> 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(),
+            None => tcx.item_name(def_id).as_str(),
+        };
+
+        let alloc = match link_name.get() {
+            "__cxa_thread_atexit_impl" => {
+                // 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)
+            }
+            _ => return err!(Unimplemented(
+                    format!("can't access foreign static: {}", link_name),
+                )),
+        };
+        Ok(Cow::Owned(alloc))
+    }
+
+    #[inline(always)]
+    fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
+    {
+        // We are not interested in detecting loops.
+        Ok(())
+    }
+
+    fn tag_allocation<'b>(
+        id: AllocId,
+        alloc: Cow<'b, Allocation>,
+        kind: Option<MemoryKind<Self::MemoryKinds>>,
+        memory: &Memory<'mir, 'tcx, Self>,
+    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
+        let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
+        let alloc = alloc.into_owned();
+        let (stacks, base_tag) = Stacks::new_allocation(
+            id,
+            Size::from_bytes(alloc.bytes.len() as u64),
+            Rc::clone(&memory.extra.stacked_borrows),
+            kind,
+        );
+        if kind != MiriMemoryKind::Static.into() {
+            assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers");
+            // Now we can rely on the inner pointers being static, too.
+        }
+        let mut memory_extra = memory.extra.stacked_borrows.borrow_mut();
+        let alloc: Allocation<Tag, Self::AllocExtra> = Allocation {
+            bytes: alloc.bytes,
+            relocations: Relocations::from_presorted(
+                alloc.relocations.iter()
+                    // The allocations in the relocations (pointers stored *inside* this allocation)
+                    // all get the base pointer tag.
+                    .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc)))
+                    .collect()
+            ),
+            undef_mask: alloc.undef_mask,
+            align: alloc.align,
+            mutability: alloc.mutability,
+            extra: AllocExtra {
+                stacked_borrows: stacks,
+                intptrcast: Default::default(),
+            },
+        };
+        (Cow::Owned(alloc), base_tag)
+    }
+
+    #[inline(always)]
+    fn tag_static_base_pointer(
+        id: AllocId,
+        memory: &Memory<'mir, 'tcx, Self>,
+    ) -> Self::PointerTag {
+        memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id)
+    }
+
+    #[inline(always)]
+    fn retag(
+        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
+        kind: mir::RetagKind,
+        place: PlaceTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx> {
+        if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) {
+            // No tracking, or no retagging. The latter is possible because a dependency of ours
+            // might be called with different flags than we are, so there are `Retag`
+            // statements but we do not want to execute them.
+            // Also, honor the whitelist in `enforce_validity` because otherwise we might retag
+            // uninitialized data.
+             Ok(())
+        } else {
+            ecx.retag(kind, place)
+        }
+    }
+
+    #[inline(always)]
+    fn stack_push(
+        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
+    ) -> InterpResult<'tcx, stacked_borrows::CallId> {
+        Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call())
+    }
+
+    #[inline(always)]
+    fn stack_pop(
+        ecx: &mut InterpretCx<'mir, 'tcx, Self>,
+        extra: stacked_borrows::CallId,
+    ) -> InterpResult<'tcx> {
+        Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra))
+    }
+
+    fn int_to_ptr(
+        int: u64,
+        memory: &Memory<'mir, 'tcx, Self>,
+    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
+        if int == 0 {
+            err!(InvalidNullPointerUsage)
+        } else if memory.extra.rng.is_none() {
+            err!(ReadBytesAsPointer)
+        } else {
+           intptrcast::GlobalState::int_to_ptr(int, memory)
+        }
+    }
+
+    fn ptr_to_int(
+        ptr: Pointer<Self::PointerTag>,
+        memory: &Memory<'mir, 'tcx, Self>,
+    ) -> InterpResult<'tcx, u64> {
+        if memory.extra.rng.is_none() {
+            err!(ReadPointerAsBytes)
+        } else {
+            intptrcast::GlobalState::ptr_to_int(ptr, memory)
+        }
+    }
+}
+
+impl AllocationExtra<Tag> for AllocExtra {
+    #[inline(always)]
+    fn memory_read<'tcx>(
+        alloc: &Allocation<Tag, AllocExtra>,
+        ptr: Pointer<Tag>,
+        size: Size,
+    ) -> InterpResult<'tcx> {
+        alloc.extra.stacked_borrows.memory_read(ptr, size)
+    }
+
+    #[inline(always)]
+    fn memory_written<'tcx>(
+        alloc: &mut Allocation<Tag, AllocExtra>,
+        ptr: Pointer<Tag>,
+        size: Size,
+    ) -> InterpResult<'tcx> {
+        alloc.extra.stacked_borrows.memory_written(ptr, size)
+    }
+
+    #[inline(always)]
+    fn memory_deallocated<'tcx>(
+        alloc: &mut Allocation<Tag, AllocExtra>,
+        ptr: Pointer<Tag>,
+        size: Size,
+    ) -> InterpResult<'tcx> {
+        alloc.extra.stacked_borrows.memory_deallocated(ptr, size)
+    }
+}
+
+impl MayLeak for MiriMemoryKind {
+    #[inline(always)]
+    fn may_leak(self) -> bool {
+        use self::MiriMemoryKind::*;
+        match self {
+            Rust | C => false,
+            Env | Static => true,
+        }
+    }
+}
diff --git a/src/memory.rs b/src/memory.rs
deleted file mode 100644 (file)
index ea8f01a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-use rand::rngs::StdRng;
-
-use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult};
-use rustc_target::abi::Size;
-
-use crate::{stacked_borrows, intptrcast};
-use crate::stacked_borrows::Tag;
-
-#[derive(Default, Clone, Debug)]
-pub struct MemoryExtra {
-    pub stacked_borrows: stacked_borrows::MemoryExtra,
-    pub intptrcast: intptrcast::MemoryExtra,
-    /// The random number generator to use if Miri is running in non-deterministic mode and to
-    /// enable intptrcast
-    pub(crate) rng: Option<StdRng>
-}
-
-#[derive(Debug, Clone)]
-pub struct AllocExtra {
-    pub stacked_borrows: stacked_borrows::AllocExtra,
-    pub intptrcast: intptrcast::AllocExtra,
-}
-
-impl AllocationExtra<Tag> for AllocExtra {
-    #[inline(always)]
-    fn memory_read<'tcx>(
-        alloc: &Allocation<Tag, AllocExtra>,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        alloc.extra.stacked_borrows.memory_read(ptr, size)
-    }
-
-    #[inline(always)]
-    fn memory_written<'tcx>(
-        alloc: &mut Allocation<Tag, AllocExtra>,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        alloc.extra.stacked_borrows.memory_written(ptr, size)
-    }
-
-    #[inline(always)]
-    fn memory_deallocated<'tcx>(
-        alloc: &mut Allocation<Tag, AllocExtra>,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        alloc.extra.stacked_borrows.memory_deallocated(ptr, size)
-    }
-}
index 572794a44add4604126d6929f6129a5c7647092c..0e25de7da5a95282c4f4b901c0d75d14b614f55a 100644 (file)
@@ -1,4 +1,4 @@
-use rustc::ty::Ty;
+use rustc::ty::{Ty, layout::{Size, LayoutOf}};
 use rustc::mir;
 
 use crate::*;