diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 57d49b2e6bc5..d7207da0b3c0 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,10 +25,14 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, - /// Whether to begin interpretation at the start_fn lang item or not + + /// Whether to begin interpretation at the start_fn lang item or not. /// - /// If false, the interpretation begins at the `main` function + /// If false, the interpretation begins at the `main` function. start_fn: bool, + + /// Whether to enforce the validity invariant. + validate: bool, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -87,7 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); let start_fn = this.start_fn; - control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); + let validate = this.validate; + control.after_analysis.callback = + Box::new(move |state| after_analysis(state, start_fn, validate)); control.after_analysis.stop = Compilation::Stop; control } @@ -101,16 +107,21 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) { +fn after_analysis<'a, 'tcx>( + state: &mut CompileState<'a, 'tcx>, + use_start_fn: bool, + validate: bool, +) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>( - TyCtxt<'a, 'tcx, 'tcx>, - &'a CompileState<'a, 'tcx> - ); + struct Visitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + state: &'a CompileState<'a, 'tcx>, + validate: bool, + }; impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { @@ -118,13 +129,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo attr.name() == "test" }) { - let did = self.0.hir.body_owner_def_id(body_id); + let did = self.tcx.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.0.def_path_debug_str(did), + self.tcx.def_path_debug_str(did), ); - miri::eval_main(self.0, did, None); - self.1.session.abort_if_errors(); + miri::eval_main(self.tcx, did, None, self.validate); + self.state.session.abort_if_errors(); } } } @@ -132,7 +143,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor(tcx, state), + &mut Visitor { tcx, state, validate } ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); @@ -142,7 +153,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo } else { None }; - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, start_wrapper, validate); state.session.abort_if_errors(); } else { @@ -221,12 +232,18 @@ fn main() { } let mut start_fn = false; + let mut validate = true; args.retain(|arg| { - if arg == "-Zmiri-start-fn" { - start_fn = true; - false - } else { - true + match arg.as_str() { + "-Zmiri-start-fn" => { + start_fn = true; + false + }, + "-Zmiri-disable-validation" => { + validate = false; + false + }, + _ => true } }); @@ -235,6 +252,7 @@ fn main() { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), start_fn, + validate, }), None, None) }); std::process::exit(result as i32); diff --git a/src/lib.rs b/src/lib.rs index 965810d0e40f..13b42d8e3c27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,11 +50,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Default::default(), + Evaluator::new(validate), Default::default(), ); @@ -145,8 +146,9 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) { - let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx"); let res: EvalResult = (|| { ecx.run()?; @@ -221,7 +223,7 @@ impl Into> for MiriMemoryKind { } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -229,6 +231,19 @@ pub struct Evaluator<'tcx> { /// 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(), + tls: TlsData::default(), + validate, + } + } } impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { @@ -241,8 +256,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); #[inline(always)] - fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - false // this is still WIP + fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + ecx.machine.validate } /// Returns Ok() when the function was handled, fail otherwise diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 82a2144a337d..151aa89be3f3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -64,6 +64,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); + flags.push("-Zmiri-disable-validation".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 0fd28d6f1e8d..dc0fa0987aeb 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,5 +1,5 @@ -// mir validation can't cope with `mem::uninitialized()`, so this test fails with validation & full-MIR. -// compile-flags: -Zmir-emit-validate=0 +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957 +// compile-flags: -Zmiri-disable-validation #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { @@ -14,4 +14,6 @@ pub fn main() { b.insert(Foo::A("/=")); b.insert(Foo::A("#")); b.insert(Foo::A("0o")); + assert!(b.remove(&Foo::A("/="))); + assert!(!b.remove(&Foo::A("/="))); } diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/call_drop_through_owned_slice.rs index 3ec6be65ed8b..b0e336c0480a 100644 --- a/tests/run-pass/call_drop_through_owned_slice.rs +++ b/tests/run-pass/call_drop_through_owned_slice.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 61c601ac6a90..94ca146db1cd 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 0bf707503112..4d89066035ce 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,3 +1,6 @@ +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54908 +// compile-flags: -Zmiri-disable-validation + use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index 8edc944c7c88..627c821a9f30 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because it checks these references too eagerly +// compile-flags: -Zmiri-disable-validation + fn main() { let x = 2usize as *const u32; // this is not aligned, but we immediately cast it to a raw ptr so that must be okay diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 66f0c84e23c1..7ca4e1a90841 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 7644da08e4af..8a48d331f454 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + #![feature(box_syntax)] use std::sync::mpsc::channel;