Merge pull request #616 from RalfJung/cargo-miri

Fix cargo miri on unit tests, refactor it a bit, set rust flag instead of feature flag
This commit is contained in:
Oliver Scherer 2019-02-07 14:44:14 +01:00 committed by GitHub
commit 1889b9fe5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 417 additions and 177 deletions

View File

@ -55,3 +55,6 @@ rustc_tests = []
[dev-dependencies]
compiletest_rs = { version = "0.3.17", features = ["tmp"] }
colored = "1.6"
[profile.release]
debug = true

View File

@ -7,10 +7,10 @@ use std::io::{self, Write, BufRead};
use std::process::Command;
use std::fs::{self, File};
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri
Usage:
cargo miri [subcommand] [options] [--] [<opts>...]
cargo miri [subcommand] [options] [--] [<miri opts>...]
Subcommands:
run Run binaries (default)
@ -22,12 +22,13 @@ Common options:
--features Features to compile for the package
-V, --version Print version info and exit
Other options are the same as `cargo rustc`.
Other [options] are the same as `cargo rustc`. Everything after the "--" is
passed verbatim to Miri.
The feature `cargo-miri` is automatically defined for convenience. You can use
The config flag `miri` is automatically defined for convenience. You can use
it to configure the resource limits
#![cfg_attr(feature = "cargo-miri", memory_size = 42)]
#![cfg_attr(miri, memory_size = 42)]
available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;
@ -53,23 +54,32 @@ fn show_error(msg: String) -> ! {
std::process::exit(1)
}
// Determines whether a --flag is present
fn has_arg_flag(name: &str) -> bool {
let mut args = std::env::args().take_while(|val| val != "--");
args.any(|val| val == name)
}
/// Gets the value of a --flag
fn get_arg_flag_value(name: &str) -> Option<String> {
// stop searching at `--`
let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--"));
match args.next() {
Some(ref p) if p == "--" => None,
Some(ref p) if p == name => args.next(),
Some(p) => {
// Make sure this really starts with `$name=`, we didn't test for the `=` yet.
let v = &p[name.len()..]; // strip leading `$name`
if v.starts_with('=') {
Some(v[1..].to_owned()) // strip leading `=`
} else {
None
let mut args = std::env::args().take_while(|val| val != "--");
loop {
let arg = match args.next() {
Some(arg) => arg,
None => return None,
};
if !arg.starts_with(name) {
continue;
}
let suffix = &arg[name.len()..]; // strip leading `name`
if suffix.is_empty() {
// This argument is exactly `name`, the next one is the value
return args.next();
} else if suffix.starts_with('=') {
// This argument is `name=value`, get the value
return Some(suffix[1..].to_owned()); // strip leading `=`
}
},
None => None,
}
}
@ -272,7 +282,17 @@ fn main() {
// each applicable target, but with the RUSTC env var set to the `cargo-miri`
// binary so that we come back in the other branch, and dispatch
// the invocations to rustc and miri, respectively.
in_cargo_miri();
} else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
// This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself:
// Dependencies get dispatched to rustc, the final test/binary to miri.
inside_cargo_rustc();
} else {
show_error(format!("Must be called with either `miri` or `rustc` as first argument."))
}
}
fn in_cargo_miri() {
let (subcommand, skip) = match std::env::args().nth(2).deref() {
Some("test") => (MiriCommand::Test, 3),
Some("run") => (MiriCommand::Run, 3),
@ -285,6 +305,7 @@ fn main() {
show_error(format!("Unknown command `{}`", s))
}
};
let verbose = has_arg_flag("-v");
// We always setup
let ask = subcommand != MiriCommand::Setup;
@ -296,54 +317,65 @@ fn main() {
// Now run the command.
for target in list_targets() {
let args = std::env::args().skip(skip);
let mut args = std::env::args().skip(skip);
let kind = target.kind.get(0).expect(
"badly formatted cargo metadata: target::kind is an empty array",
);
// Now we run `cargo rustc $FLAGS $ARGS`, giving the user the
// change to add additional flags. "FLAGS" is set to identify
// this target. The user gets to control what gets actually passed to Miri.
// However, we need to add a flag to what gets passed to rustc for the finaly
// binary, so that we know to interpret that with Miri.
// So after the first "--", we add "-Zcargo-miri-marker".
let mut cmd = Command::new("cargo");
cmd.arg("rustc");
match (subcommand, &kind[..]) {
(MiriCommand::Test, "test") => {
// For test binaries we call `cargo rustc --test target -- <rustc args>`
if let Err(code) = process(
vec!["--test".to_string(), target.name].into_iter().chain(
args,
),
)
{
std::process::exit(code);
}
}
(MiriCommand::Test, "lib") => {
// For libraries we call `cargo rustc -- --test <rustc args>`
// 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 then execute that harness just like any other binary.
if let Err(code) = process(
vec!["--".to_string(), "--test".to_string()].into_iter().chain(
args,
),
)
{
std::process::exit(code);
}
}
(MiriCommand::Run, "bin") => {
// For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
if let Err(code) = process(
vec!["--bin".to_string(), target.name].into_iter().chain(
args,
),
)
{
std::process::exit(code);
// FIXME: We just run all the binaries here.
// We should instead support `cargo miri --bin foo`.
cmd.arg("--bin").arg(target.name);
}
(MiriCommand::Test, "test") => {
cmd.arg("--test").arg(target.name);
}
_ => {}
(MiriCommand::Test, "lib") |
(MiriCommand::Test, "bin") => {
cmd.arg(format!("--{}", kind)).arg(target.name).arg("--profile").arg("test");
}
// The remaining targets we do not even want to build
_ => continue,
}
// add user-defined args until first "--"
while let Some(arg) = args.next() {
if arg == "--" {
break;
}
cmd.arg(arg);
}
// add "--" "-Zcargo-miri-marker" and the remaining user flags
cmd
.arg("--")
.arg("cargo-miri-marker")
.args(args);
let path = std::env::current_exe().expect("current executable path invalid");
cmd.env("RUSTC_WRAPPER", path);
if verbose {
eprintln!("+ {:?}", cmd);
}
} else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
// This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself:
// Dependencies get dispatched to rustc, the final test/binary to miri.
let exit_status = cmd
.spawn()
.expect("could not run cargo")
.wait()
.expect("failed to wait for cargo?");
if !exit_status.success() {
std::process::exit(exit_status.code().unwrap_or(-1))
}
}
}
fn inside_cargo_rustc() {
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
@ -377,12 +409,18 @@ fn main() {
.collect()
};
args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
// this check ensures that dependencies are built but not interpreted and the final crate is
// interpreted but not built
let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");
let mut command = if miri_enabled {
// see if we have cargo-miri-marker, which means we want to interpret this crate in Miri
// (and remove the marker).
let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") {
args.remove(pos);
true
} else {
false
};
let mut command = if needs_miri {
let mut path = std::env::current_exe().expect("current executable path invalid");
path.set_file_name("miri");
Command::new(path)
@ -390,6 +428,9 @@ fn main() {
Command::new("rustc")
};
command.args(&args);
if has_arg_flag("-v") {
eprintln!("+ {:?}", command);
}
match command.status() {
Ok(exit) => {
@ -397,42 +438,7 @@ fn main() {
std::process::exit(exit.code().unwrap_or(42));
}
}
Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e),
Err(ref e) => panic!("error during rustc call: {:?}", e),
}
} else {
show_error(format!("Must be called with either `miri` or `rustc` as first argument."))
}
}
fn process<I>(old_args: I) -> Result<(), i32>
where
I: Iterator<Item = String>,
{
let mut args = vec!["rustc".to_owned()];
let mut found_dashes = false;
for arg in old_args {
found_dashes |= arg == "--";
args.push(arg);
}
if !found_dashes {
args.push("--".to_owned());
}
args.push("--emit=dep-info,metadata".to_owned());
let path = std::env::current_exe().expect("current executable path invalid");
let exit_status = Command::new("cargo")
.args(&args)
.env("RUSTC_WRAPPER", path)
.spawn()
.expect("could not run cargo")
.wait()
.expect("failed to wait for cargo?");
if exit_status.success() {
Ok(())
} else {
Err(exit_status.code().unwrap_or(-1))
}
}

View File

@ -54,7 +54,7 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem};
pub fn miri_default_args() -> &'static [&'static str] {
// The flags here should be kept in sync with what bootstrap adds when `test-miri` is
// set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources.
&["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"]
&["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"]
}
// Used by priroda

View File

@ -1,3 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.0.0"
@ -8,7 +20,192 @@ name = "cargo-miri-test"
version = "0.1.0"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0"
"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -6,3 +6,6 @@ edition = "2018"
[dependencies]
byteorder = "1.0"
[dev-dependencies]
rand = "0.6.5"

View File

@ -1,3 +1,7 @@
extern crate byteorder;
#[cfg(test)]
extern crate rand;
use byteorder::{BigEndian, ByteOrder};
fn main() {
@ -7,3 +11,17 @@ fn main() {
println!("{:#010x}", n);
eprintln!("standard error");
}
#[cfg(test)]
mod test {
use rand::{Rng, SeedableRng};
// Make sure in-crate tests with dev-dependencies work
#[test]
fn rng() {
let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef);
let x: u32 = rng.gen();
let y: u32 = rng.gen();
assert_ne!(x, y);
}
}

View File

@ -1,7 +1,13 @@
running 1 test
test test::rng ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
running 2 tests
test bar ... ok
test baz ... ok
test rng ... ok
test simple ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

View File

@ -1,17 +1,24 @@
extern crate rand;
use rand::{Rng, SeedableRng};
#[test]
fn bar() {
fn simple() {
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);
fn rng() {
let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe);
let x: u32 = rng.gen();
let y: u32 = rng.gen();
assert_ne!(x, y);
}
// A test that won't work on miri
#[cfg(not(feature = "cargo-miri"))]
#[cfg(not(miri))]
#[test]
fn does_not_work_on_miri() {
let x = 0u8;