Skip to content

Commit 1f68737

Browse files
authored
Merge pull request #550 from RalfJung/cargo-miri-test
Fix cargo miri test
2 parents 3a93831 + 4e0fe62 commit 1f68737

File tree

10 files changed

+68
-65
lines changed

10 files changed

+68
-65
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-12-14
1+
nightly-2018-12-18

src/bin/cargo-miri.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ fn setup(ask_user: bool) {
171171
} else {
172172
println!("Installing xargo: `cargo install xargo -f`");
173173
}
174-
// FIXME: Go back to using releases, once a 0.3.13 got released.
175-
if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() {
174+
if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() {
176175
show_error(format!("Failed to install xargo"));
177176
}
178177
}
@@ -310,9 +309,8 @@ fn main() {
310309
(MiriCommand::Test, "lib") => {
311310
// For libraries we call `cargo rustc -- --test <rustc args>`
312311
// Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
313-
// rustc to build a test harness which calls all #[test] functions. We don't
314-
// use the harness since we execute each #[test] function's MIR ourselves before
315-
// compilation even completes, but this option is necessary to build the library.
312+
// rustc to build a test harness which calls all #[test] functions.
313+
// We then execute that harness just like any other binary.
316314
if let Err(code) = process(
317315
vec!["--".to_string(), "--test".to_string()].into_iter().chain(
318316
args,

src/bin/miri.rs

+6-39
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ use rustc_metadata::cstore::CStore;
2323
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
2424
use rustc_driver::driver::{CompileState, CompileController};
2525
use rustc::session::config::{self, Input, ErrorOutputType};
26-
use rustc::hir::{self, itemlikevisit};
27-
use rustc::ty::TyCtxt;
2826
use rustc_codegen_utils::codegen_backend::CodegenBackend;
2927
use syntax::ast;
3028

@@ -115,43 +113,12 @@ fn after_analysis<'a, 'tcx>(
115113

116114
let tcx = state.tcx.unwrap();
117115

118-
if std::env::args().any(|arg| arg == "--test") {
119-
struct Visitor<'a, 'tcx: 'a> {
120-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
121-
state: &'a CompileState<'a, 'tcx>,
122-
validate: bool,
123-
};
124-
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
125-
fn visit_item(&mut self, i: &'hir hir::Item) {
126-
if let hir::ItemKind::Fn(.., body_id) = i.node {
127-
if i.attrs.iter().any(|attr| {
128-
attr.name() == "test"
129-
})
130-
{
131-
let did = self.tcx.hir().body_owner_def_id(body_id);
132-
println!(
133-
"running test: {}",
134-
self.tcx.def_path_debug_str(did),
135-
);
136-
miri::eval_main(self.tcx, did, self.validate);
137-
self.state.session.abort_if_errors();
138-
}
139-
}
140-
}
141-
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
142-
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
143-
}
144-
state.hir_crate.unwrap().visit_all_item_likes(
145-
&mut Visitor { tcx, state, validate }
146-
);
147-
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
148-
let entry_def_id = tcx.hir().local_def_id(entry_node_id);
149-
miri::eval_main(tcx, entry_def_id, validate);
150-
151-
state.session.abort_if_errors();
152-
} else {
153-
println!("no main function found, assuming auxiliary build");
154-
}
116+
let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!");
117+
let entry_def_id = tcx.hir().local_def_id(entry_node_id);
118+
119+
miri::eval_main(tcx, entry_def_id, validate);
120+
121+
state.session.abort_if_errors();
155122
}
156123

157124
fn init_early_loggers() {

src/fn_call.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
426426
let paths = &[
427427
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
428428
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
429+
(&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
429430
];
430431
let mut result = None;
431432
for &(path, path_value) in paths {
@@ -452,6 +453,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
452453
}
453454
}
454455

456+
"isatty" => {
457+
this.write_null(dest)?;
458+
}
459+
455460
// Hook pthread calls that go to the thread-local storage memory subsystem
456461
"pthread_key_create" => {
457462
let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
@@ -508,10 +513,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
508513
this.write_null(dest)?;
509514
}
510515

511-
"_tlv_atexit" => {
512-
// FIXME: Register the dtor
513-
},
514-
515516
// Determining stack base address
516517
"pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
517518
"pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
@@ -549,7 +550,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
549550
this.write_null(dest)?;
550551
}
551552

552-
// Windows API subs
553+
// macOS API stubs
554+
"_tlv_atexit" => {
555+
// FIXME: Register the dtor
556+
},
557+
"_NSGetArgc" => {
558+
this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
559+
},
560+
"_NSGetArgv" => {
561+
this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
562+
},
563+
564+
// Windows API stubs
553565
"AddVectoredExceptionHandler" => {
554566
// any non zero value works for the stdlib. This is just used for stackoverflows anyway
555567
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
@@ -571,8 +583,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
571583
// this is c::ERROR_CALL_NOT_IMPLEMENTED
572584
this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?;
573585
},
574-
575-
// Windows TLS
576586
"TlsAlloc" => {
577587
// This just creates a key; Windows does not natively support TLS dtors.
578588

src/lib.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
121121

122122
// Second argument (argc): 1
123123
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
124-
ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
124+
let argc = Scalar::from_int(1, dest.layout.size);
125+
ecx.write_scalar(argc, dest)?;
126+
let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
127+
ecx.write_scalar(argc, argc_place.into())?;
128+
ecx.machine.argc = Some(argc_place.ptr.to_ptr()?);
125129

126130
// FIXME: extract main source file path
127131
// Third argument (argv): &[b"foo"]
@@ -132,7 +136,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
132136
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
133137
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
134138
ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?;
135-
ecx.write_scalar(foo_place.ptr, dest)?;
139+
let argv = foo_place.ptr;
140+
ecx.write_scalar(argv, dest)?;
141+
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
142+
ecx.write_scalar(argv, argv_place.into())?;
143+
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
136144

137145
assert!(args.next().is_none(), "start lang item has more arguments than expected");
138146

@@ -253,6 +261,11 @@ pub struct Evaluator<'tcx> {
253261
/// Miri does not expose env vars from the host to the emulated program
254262
pub(crate) env_vars: HashMap<Vec<u8>, Pointer<Borrow>>,
255263

264+
/// Program arguments (`Option` because we can only initialize them after creating the ecx).
265+
/// These are *pointers* to argc/argv because macOS.
266+
pub(crate) argc: Option<Pointer<Borrow>>,
267+
pub(crate) argv: Option<Pointer<Borrow>>,
268+
256269
/// TLS state
257270
pub(crate) tls: TlsData<'tcx>,
258271

@@ -267,6 +280,8 @@ impl<'tcx> Evaluator<'tcx> {
267280
fn new(validate: bool) -> Self {
268281
Evaluator {
269282
env_vars: HashMap::default(),
283+
argc: None,
284+
argv: None,
270285
tls: TlsData::default(),
271286
validate,
272287
stacked_borrows: stacked_borrows::State::default(),

test-cargo-miri/run-test.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
import sys, subprocess
99

10-
def test_cargo_miri():
11-
print("==> Testing `cargo miri run` <==")
10+
def test(name, cmd, stdout_ref, stderr_ref):
11+
print("==> Testing `{}` <==".format(name))
1212
## Call `cargo miri`, capture all output
1313
p = subprocess.Popen(
14-
["cargo", "miri", "run", "-q"],
14+
cmd,
1515
stdout=subprocess.PIPE,
1616
stderr=subprocess.PIPE
1717
)
@@ -26,17 +26,19 @@ def test_cargo_miri():
2626
# Test for failures
2727
if p.returncode != 0:
2828
sys.exit(1)
29-
if stdout != open('stdout.ref').read():
29+
if stdout != open(stdout_ref).read():
3030
print("stdout does not match reference")
3131
sys.exit(1)
32-
if stderr != open('stderr.ref').read():
32+
if stderr != open(stderr_ref).read():
3333
print("stderr does not match reference")
3434
sys.exit(1)
3535

36+
def test_cargo_miri_run():
37+
test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref")
38+
3639
def test_cargo_miri_test():
37-
print("==> Testing `cargo miri test` <==")
38-
subprocess.check_call(["cargo", "miri", "test"])
40+
test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref")
3941

40-
test_cargo_miri()
42+
test_cargo_miri_run()
4143
test_cargo_miri_test()
4244
sys.exit(0)

test-cargo-miri/test.stderr.ref

Whitespace-only changes.

test-cargo-miri/test.stdout.ref

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
running 2 tests
3+
test bar ... ok
4+
test baz ... ok
5+
6+
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
7+

test-cargo-miri/tests/foo.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,10 @@
22
fn bar() {
33
assert_eq!(4, 4);
44
}
5+
6+
// Having more than 1 test does seem to make a difference
7+
// (i.e., this calls ptr::swap which having just one test does not).
8+
#[test]
9+
fn baz() {
10+
assert_eq!(5, 5);
11+
}

tests/run-pass/btreemap.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957
2-
// compile-flags: -Zmiri-disable-validation
3-
41
#[derive(PartialEq, Eq, PartialOrd, Ord)]
52
pub enum Foo {
63
A(&'static str),

0 commit comments

Comments
 (0)