From f31bb43804fd70452eb8e20f83065aad186f8ec5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:08 +0100 Subject: [PATCH 1/9] implement some libc hooks needed by libtest --- src/fn_call.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 5d41848b64..8909223a31 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -426,6 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let paths = &[ (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), + (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -452,6 +453,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } + "isatty" => { + self.write_null(dest)?; + } + // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { let key_ptr = this.read_scalar(args[0])?.to_ptr()?; From 9417b28de55888d99aeefcd03243294b658b4d97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:23 +0100 Subject: [PATCH 2/9] treat test binaries like all others --- src/bin/cargo-miri.rs | 5 ++--- src/bin/miri.rs | 45 ++++++------------------------------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 7e1785fd3b..179f11dd56 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -279,9 +279,8 @@ fn main() { (MiriCommand::Test, "lib") => { // For libraries we call `cargo rustc -- --test ` // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells - // rustc to build a test harness which calls all #[test] functions. We don't - // use the harness since we execute each #[test] function's MIR ourselves before - // compilation even completes, but this option is necessary to build the library. + // rustc to build a test harness which calls all #[test] functions. + // We then execute that harness just like any other binary. if let Err(code) = process( vec!["--".to_string(), "--test".to_string()].into_iter().chain( args, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e88c13305d..c2255d7063 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -23,8 +23,6 @@ use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; -use rustc::hir::{self, itemlikevisit}; -use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; @@ -115,43 +113,12 @@ fn after_analysis<'a, 'tcx>( let tcx = state.tcx.unwrap(); - if std::env::args().any(|arg| arg == "--test") { - 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 { - if i.attrs.iter().any(|attr| { - attr.name() == "test" - }) - { - let did = self.tcx.hir().body_owner_def_id(body_id); - println!( - "running test: {}", - self.tcx.def_path_debug_str(did), - ); - miri::eval_main(self.tcx, did, self.validate); - self.state.session.abort_if_errors(); - } - } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - state.hir_crate.unwrap().visit_all_item_likes( - &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); - miri::eval_main(tcx, entry_def_id, validate); - - state.session.abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); - } + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!"); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); + + miri::eval_main(tcx, entry_def_id, validate); + + state.session.abort_if_errors(); } fn init_early_loggers() { From 3fda8294bdc8dedfc299cd15d0d40c19d7da598f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:51 +0100 Subject: [PATCH 3/9] test cargo miri test output when testing cargo miri --- test-cargo-miri/run-test.py | 19 +++++++++++-------- test-cargo-miri/test.stderr.ref | 0 test-cargo-miri/test.stdout.ref | 7 +++++++ test-cargo-miri/tests/foo.rs | 7 +++++++ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 test-cargo-miri/test.stderr.ref create mode 100644 test-cargo-miri/test.stdout.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 42745535e0..c7ab8f14df 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,11 +7,11 @@ import sys, subprocess -def test_cargo_miri(): - print("==> Testing `cargo miri run` <==") +def test(name, cmd, stdout_ref, stderr_ref): + print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output p = subprocess.Popen( - ["cargo", "miri", "run", "-q"], + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) @@ -26,17 +26,20 @@ def test_cargo_miri(): # Test for failures if p.returncode != 0: sys.exit(1) - if stdout != open('stdout.ref').read(): + if stdout != open(stdout_ref).read(): print("stdout does not match reference") sys.exit(1) - if stderr != open('stderr.ref').read(): + if stderr != open(stderr_ref).read(): print("stderr does not match reference") sys.exit(1) +def test_cargo_miri_run(): + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") + def test_cargo_miri_test(): - print("==> Testing `cargo miri test` <==") - subprocess.check_call(["cargo", "miri", "test"]) + # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 + test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") -test_cargo_miri() +test_cargo_miri_run() test_cargo_miri_test() sys.exit(0) diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref new file mode 100644 index 0000000000..94fd56b0cd --- /dev/null +++ b/test-cargo-miri/test.stdout.ref @@ -0,0 +1,7 @@ + +running 2 tests +test bar ... ok +test baz ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/foo.rs index fb7fad21c9..9827ae82d6 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/foo.rs @@ -2,3 +2,10 @@ fn bar() { assert_eq!(4, 4); } + +// Having more than 1 test does seem to make a difference +// (i.e., this calls ptr::swap which having just one test does not). +#[test] +fn baz() { + assert_eq!(5, 5); +} From ce5089c3905f7051a9bcdc92ef24ba934dc75098 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 17:54:39 +0100 Subject: [PATCH 4/9] rebase fallout --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8909223a31..d11364ce0d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -454,7 +454,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "isatty" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Hook pthread calls that go to the thread-local storage memory subsystem From 3e603c38d74935689d7454ec961c49ab2470bf46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:40:06 +0100 Subject: [PATCH 5/9] bump Rust version, fix test-cargo-miri and it no longer needs to disable validation --- rust-version | 2 +- test-cargo-miri/run-test.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 2ad896fe05..d1ff80dec0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-14 +nightly-2018-12-18 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c7ab8f14df..19e0a14740 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -34,11 +34,10 @@ def test(name, cmd, stdout_ref, stderr_ref): sys.exit(1) def test_cargo_miri_run(): - test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") def test_cargo_miri_test(): - # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 - test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") + test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") test_cargo_miri_run() test_cargo_miri_test() From b3f799136778a1d034bc621bc41ed42a68d1cc48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:41:52 +0100 Subject: [PATCH 6/9] btree is fixed --- tests/run-pass/btreemap.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index dc0fa0987a..b7140d72ac 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,6 +1,3 @@ -// 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 { A(&'static str), From e8c53e81f8ec8de08cc1f2a1c026c9055fc37445 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:26:57 +0100 Subject: [PATCH 7/9] implement macOS functions for argc, argv --- src/fn_call.rs | 19 ++++++++++++------- src/lib.rs | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d11364ce0d..ab82223f23 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -513,10 +513,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - "_tlv_atexit" => { - // FIXME: Register the dtor - }, - // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { @@ -554,7 +550,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // Windows API subs + // macOS API stubs + "_tlv_atexit" => { + // FIXME: Register the dtor + }, + "_NSGetArgc" => { + this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; + }, + "_NSGetArgv" => { + this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; + }, + + // Windows API stubs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -576,8 +583,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // this is c::ERROR_CALL_NOT_IMPLEMENTED this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, - - // Windows TLS "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. diff --git a/src/lib.rs b/src/lib.rs index 28639976aa..e6e1a338c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,7 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + let argc = Scalar::from_int(1, dest.layout.size); + ecx.write_scalar(argc, dest)?; + 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): &[b"foo"] @@ -132,7 +136,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - ecx.write_scalar(foo_place.ptr, dest)?; + let argv = foo_place.ptr; + ecx.write_scalar(argv, dest)?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -253,6 +261,11 @@ pub struct Evaluator<'tcx> { /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, + /// Program arguments (`Option` because we can only initialize them after creating the ecx). + /// These are *pointers* to argc/argv because macOS. + pub(crate) argc: Option>, + pub(crate) argv: Option>, + /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -267,6 +280,8 @@ impl<'tcx> Evaluator<'tcx> { fn new(validate: bool) -> Self { Evaluator { env_vars: HashMap::default(), + argc: None, + argv: None, tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), From e4fd710606c346cad3e64dc7edc18201699560c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:41:32 +0100 Subject: [PATCH 8/9] there is a new xargo released, use that --- src/bin/cargo-miri.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2a2cbdb815..0a8ddd95a7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -171,8 +171,7 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - // FIXME: Go back to using releases, once a 0.3.13 got released. - if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 4e0fe62bd90bffcec376e7b0877e87ebfece3cfb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:45:10 +0100 Subject: [PATCH 9/9] typo --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e6e1a338c9..e41a92e55f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected");