X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmachine.rs;h=ed9a8a1c46346f320149b1a9e473cbc56e3e124a;hb=068c448832c466e3eb6297125a12e5a83a450e2d;hp=0ddb2d40b8e8575f0eabe9d9459a6fd480796983;hpb=ce5e910e602a46c7e18a6f2f731ddac971da8fdb;p=rust.git diff --git a/src/machine.rs b/src/machine.rs index 0ddb2d40b8e..ed9a8a1c463 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,3 +1,6 @@ +//! Global machine state as well as implementation of the interpreter engine +//! `Machine` trait. + use std::rc::Rc; use std::borrow::Cow; use std::collections::HashMap; @@ -8,14 +11,15 @@ use syntax::attr; use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt}; +use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra memory kinds @@ -25,6 +29,8 @@ pub enum MiriMemoryKind { Rust, /// `malloc` memory. C, + /// Windows `HeapAlloc` memory. + WinHeap, /// Part of env var emulation. Env, /// Statics. @@ -46,25 +52,24 @@ pub struct AllocExtra { } /// Extra global memory data -#[derive(Default, Clone, Debug)] +#[derive(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>, + /// The random number generator used for resolving non-determinism. + pub(crate) rng: RefCell, /// Whether to enforce the validity invariant. pub(crate) validate: bool, } impl MemoryExtra { - pub fn new(rng: Option, validate: bool) -> Self { + pub fn new(rng: StdRng, validate: bool) -> Self { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), - rng: rng.map(RefCell::new), + rng: RefCell::new(rng), validate, } } @@ -88,10 +93,13 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, + + /// If enabled, the `env_vars` field is populated with the host env vars during initialization. + pub(crate) communicate: bool, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new() -> Self { + pub(crate) fn new(communicate: bool) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -99,12 +107,13 @@ pub(crate) fn new() -> Self { cmd_line: None, last_error: 0, tls: TlsData::default(), + communicate, } } } -/// A rustc InterpretCx for Miri. -pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; +/// A rustc InterpCx for Miri. +pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { @@ -130,20 +139,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; + type ExtraFnVal = Dlsym; type MemoryMap = MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + const CHECK_ALIGN: bool = true; + #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.memory().extra.validate } - /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, @@ -152,9 +163,20 @@ fn find_fn( ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] + fn call_extra_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + ecx.call_dlsym(fn_val, args, dest, ret) + } + #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, @@ -163,17 +185,17 @@ fn call_intrinsic( } #[inline(always)] - fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + fn binary_ptr_op( + ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, right) + ecx.binary_ptr_op(bin_op, left, right) } fn box_alloc( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -197,12 +219,12 @@ fn box_alloc( // 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 arg = ecx.local_place(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 arg = ecx.local_place(args.next().unwrap())?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; @@ -215,8 +237,8 @@ fn box_alloc( } fn find_foreign_static( + tcx: TyCtxt<'tcx>, 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) { @@ -231,35 +253,33 @@ fn find_foreign_static( 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), - )), + _ => throw_unsup_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> + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) } fn tag_allocation<'b>( + memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - memory: &Memory<'mir, 'tcx, Self>, ) -> (Cow<'b, Allocation>, 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) = if !memory.extra.validate { + let (stacks, base_tag) = if !memory_extra.validate { (None, Tag::Untagged) } else { let (stacks, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), + Rc::clone(&memory_extra.stacked_borrows), kind, ); (Some(stacks), base_tag) @@ -268,7 +288,7 @@ fn tag_allocation<'b>( 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 mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -276,10 +296,10 @@ fn tag_allocation<'b>( // The allocations in the relocations (pointers stored *inside* this allocation) // all get the base pointer tag. .map(|&(offset, ((), alloc))| { - let tag = if !memory.extra.validate { + let tag = if !memory_extra.validate { Tag::Untagged } else { - memory_extra.static_base_ptr(alloc) + stacked_borrows.static_base_ptr(alloc) }; (offset, (tag, alloc)) }) @@ -297,19 +317,19 @@ fn tag_allocation<'b>( #[inline(always)] fn tag_static_base_pointer( + memory_extra: &MemoryExtra, id: AllocId, - memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - if !memory.extra.validate { + if !memory_extra.validate { Tag::Untagged } else { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) } } #[inline(always)] fn retag( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { @@ -323,41 +343,33 @@ fn retag( #[inline(always)] fn stack_push( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'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>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) } + #[inline(always)] fn int_to_ptr( - int: u64, memory: &Memory<'mir, 'tcx, Self>, + int: u64, ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - err!(InvalidNullPointerUsage) - } else if memory.extra.rng.is_none() { - err!(ReadBytesAsPointer) - } else { - intptrcast::GlobalState::int_to_ptr(int, memory) - } + intptrcast::GlobalState::int_to_ptr(int, memory) } + #[inline(always)] fn ptr_to_int( - ptr: Pointer, memory: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, ) -> InterpResult<'tcx, u64> { - if memory.extra.rng.is_none() { - err!(ReadPointerAsBytes) - } else { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } + intptrcast::GlobalState::ptr_to_int(ptr, memory) } } @@ -407,7 +419,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C => false, + Rust | C | WinHeap => false, Env | Static => true, } }