Merge pull request #104 from oli-obk/cargo

add cargo-miri subcommand
This commit is contained in:
Scott Olson 2017-01-28 15:42:54 -08:00 committed by GitHub
commit dc336eecac
10 changed files with 385 additions and 17 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
/target
target
/doc
tex/*/out
*.dot

View file

@ -10,8 +10,14 @@ before_script:
- sh ~/rust-installer/rustup.sh --add-target=i686-pc-windows-msvc --prefix=/home/travis/rust -y --disable-sudo
script:
- |
env RUST_SYSROOT=$HOME/rust travis-cargo build &&
env RUST_SYSROOT=$HOME/rust travis-cargo test
export RUST_SYSROOT=$HOME/rust &&
travis-cargo build &&
travis-cargo test &&
travis-cargo install &&
cd cargo-miri-test &&
cargo miri &&
cargo miri test &&
cd ..
notifications:
email:
on_success: never

99
Cargo.lock generated
View file

@ -3,6 +3,7 @@ name = "miri"
version = "0.1.0"
dependencies = [
"byteorder 1.0.0 (git+https://github.com/quininer/byteorder.git?branch=i128)",
"cargo_metadata 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"compiletest_rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -22,6 +23,16 @@ name = "byteorder"
version = "1.0.0"
source = "git+https://github.com/quininer/byteorder.git?branch=i128#ef51df297aa833d0b6639aae328a95597fc07d75"
[[package]]
name = "cargo_metadata"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "compiletest_rs"
version = "0.2.5"
@ -31,6 +42,11 @@ dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "env_logger"
version = "0.3.5"
@ -40,6 +56,11 @@ dependencies = [
"regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@ -80,6 +101,16 @@ dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "0.1.77"
@ -102,6 +133,57 @@ name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "0.9.0-rc3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_codegen"
version = "0.9.0-rc3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_codegen_internals"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "0.9.0-rc3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_codegen 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "0.9.0-rc2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
@ -119,6 +201,11 @@ dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "0.1.3"
@ -137,19 +224,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum byteorder 1.0.0 (git+https://github.com/quininer/byteorder.git?branch=i128)" = "<none>"
"checksum cargo_metadata 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb382367db7c8eb427e622e46b99eff500fb63d8cf22dc2df6bcc5587112a993"
"checksum compiletest_rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f344389765ad7bec166f64c1b39ed6dd2b54d81c4c5dd8af789169351d380c"
"checksum dtoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80e5dc7a4b2bbf348fb0afe68b3994daf1126223d2d9770221b8213c5e4565af"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum itoa 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8f9e7653c775f2ef8016f4181eb3ad62fe8a710e5dd73d4060a5903a58022f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
"checksum quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b44fd83db28b83c1c58187159934906e5e955c812e211df413b76b03c909a5"
"checksum regex 0.1.77 (registry+https://github.com/rust-lang/crates.io-index)" = "64b03446c466d35b42f2a8b203c8e03ed8b91c0f17b56e1f84f7210a257aa665"
"checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum serde 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)" = "bfeedfddd5db4465d96959431d7f3d8d618a6052cdaf3fddb2e981e86a7ad04c"
"checksum serde_codegen 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)" = "c89a070576ea7af4c609e72fcdd3d283e9c4c77946bd3fd7a07c43ee15b9c144"
"checksum serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "afad7924a009f859f380e4a2e3a509a845c2ac66435fcead74a4d983b21ae806"
"checksum serde_derive 0.9.0-rc3 (registry+https://github.com/rust-lang/crates.io-index)" = "1651978181e36fc90e1faaf91ae21fe74ffba77bc4ce4baf18b20fbb00e24cd4"
"checksum serde_json 0.9.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)" = "6efad3dc934e5032a92ea163adb13c8414359da950a0f304c1897214f28d9444"
"checksum syn 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "17134635792e6a2361f53efbee798701796d8b5842c1c21b7cdb875e2950c8fc"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View file

@ -11,6 +11,11 @@ doc = false
name = "miri"
test = false
[[bin]]
doc = false
name = "cargo-miri"
test = false
[lib]
test = false
@ -20,6 +25,7 @@ byteorder = { git = "https://github.com/quininer/byteorder.git", branch = "i128"
env_logger = "0.3.3"
log = "0.3.6"
log_settings = "0.1.1"
cargo_metadata = "0.1"
[dev-dependencies]
compiletest_rs = "0.2.5"

4
cargo-miri-test/Cargo.lock generated Normal file
View file

@ -0,0 +1,4 @@
[root]
name = "cargo-miri-test"
version = "0.1.0"

View file

@ -0,0 +1,6 @@
[package]
name = "cargo-miri-test"
version = "0.1.0"
authors = ["Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>"]
[dependencies]

View file

@ -0,0 +1,3 @@
fn main() {
assert_eq!(5, 5);
}

View file

@ -0,0 +1,4 @@
#[test]
fn bar() {
assert_eq!(4, 4);
}

184
src/bin/cargo-miri.rs Normal file
View file

@ -0,0 +1,184 @@
#![feature(static_in_const)]
extern crate cargo_metadata;
use std::path::{PathBuf, Path};
use std::io::Write;
use std::process::Command;
const CARGO_MIRI_HELP: &str = r#"Interprets bin crates
Usage:
cargo miri [options] [--] [<opts>...]
Common options:
-h, --help Print this message
--features Features to compile for the package
-V, --version Print version info and exit
Other options are the same as `cargo rustc`.
The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits
#![cfg_attr(feature = "cargo-miri", memory_size = 42)]
available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;
fn show_help() {
println!("{}", CARGO_MIRI_HELP);
}
fn show_version() {
println!("{}", env!("CARGO_PKG_VERSION"));
}
fn main() {
// Check for version and help flags even when invoked as 'cargo-miri'
if std::env::args().any(|a| a == "--help" || a == "-h") {
show_help();
return;
}
if std::env::args().any(|a| a == "--version" || a == "-V") {
show_version();
return;
}
let dep_path = std::env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps");
if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
// this arm is when `cargo miri` is called
let test = std::env::args().nth(2).map_or(false, |text| text == "test");
let skip = if test { 3 } else { 2 };
let manifest_path_arg = std::env::args().skip(skip).find(|val| val.starts_with("--manifest-path="));
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
metadata
} else {
let _ = std::io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata."));
std::process::exit(101);
};
let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..])));
let current_dir = std::env::current_dir();
let package_index = metadata.packages
.iter()
.position(|package| {
let package_manifest_path = Path::new(&package.manifest_path);
if let Some(ref manifest_path) = manifest_path {
package_manifest_path == manifest_path
} else {
let current_dir = current_dir.as_ref().expect("could not read current directory");
let package_manifest_directory = package_manifest_path.parent()
.expect("could not find parent directory of package manifest");
package_manifest_directory == current_dir
}
})
.expect("could not find matching package");
let package = metadata.packages.remove(package_index);
for target in package.targets {
let args = std::env::args().skip(skip);
let kind = target.kind.get(0).expect("badly formatted cargo metadata: target::kind is an empty array");
if test && kind == "test" {
if let Err(code) = process(vec!["--test".to_string(), target.name].into_iter().chain(args),
&dep_path) {
std::process::exit(code);
}
} else if !test && kind == "bin" {
if let Err(code) = process(vec!["--bin".to_string(), target.name].into_iter().chain(args),
&dep_path) {
std::process::exit(code);
}
}
}
} else {
// this arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself
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 (Some(home), Some(toolchain)) = (home, toolchain) {
format!("{}/toolchains/{}", home, toolchain)
} else {
option_env!("SYSROOT")
.map(|s| s.to_owned())
.or_else(|| {
Command::new("rustc")
.arg("--print")
.arg("sysroot")
.output()
.ok()
.and_then(|out| String::from_utf8(out.stdout).ok())
.map(|s| s.trim().to_owned())
})
.expect("need to specify SYSROOT env var during miri compilation, or use rustup or multirust")
};
// this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly
// without having to pass --sysroot or anything
let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
std::env::args().skip(1).collect()
} else {
std::env::args().skip(1).chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect()
};
// 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 == "-Zno-trans");
if miri_enabled {
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
}
let mut path = std::env::current_exe().expect("current executable path invalid");
path.set_file_name("miri");
match Command::new(path).args(&args).status() {
Ok(exit) => if !exit.success() {
std::process::exit(exit.code().unwrap_or(42));
},
Err(e) => panic!("error during miri run: {:?}", e),
}
}
}
fn process<P, I>(old_args: I, dep_path: P) -> Result<(), i32>
where P: AsRef<Path>,
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("-L".to_owned());
args.push(dep_path.as_ref().to_string_lossy().into_owned());
args.push("-Zno-trans".to_owned());
args.push("--cfg".to_owned());
args.push(r#"feature="cargo-miri""#.to_owned());
let path = std::env::current_exe().expect("current executable path invalid");
let exit_status = std::process::Command::new("cargo")
.args(&args)
.env("RUSTC", 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

@ -4,21 +4,57 @@ extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
#[macro_use] extern crate log;
use rustc::session::Session;
use rustc_driver::{Compilation, CompilerCalls};
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use syntax::ast::{MetaItemKind, NestedMetaItemKind};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use std::path::PathBuf;
struct MiriCompilerCalls;
struct MiriCompilerCalls(RustcDefaultCalls);
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a> {
let mut control = CompileController::basic();
fn early_callback(
&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
cfg: &ast::CrateConfig,
descriptions: &rustc_errors::registry::Registry,
output: ErrorOutputType
) -> Compilation {
self.0.early_callback(matches, sopts, cfg, descriptions, output)
}
fn no_input(
&mut self,
matches: &getopts::Matches,
sopts: &config::Options,
cfg: &ast::CrateConfig,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
descriptions: &rustc_errors::registry::Registry
) -> Option<(Input, Option<PathBuf>)> {
self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
}
fn late_callback(
&mut self,
matches: &getopts::Matches,
sess: &Session,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>
) -> Compilation {
self.0.late_callback(matches, sess, input, odir, ofile)
}
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
let mut control = self.0.build_controller(sess, matches);
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
control.after_analysis.callback = Box::new(after_analysis);
if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) {
@ -34,19 +70,39 @@ fn after_hir_lowering(state: &mut CompileState) {
state.session.plugin_attributes.borrow_mut().push(attr);
}
fn after_analysis(state: &mut CompileState) {
fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
state.session.abort_if_errors();
let tcx = state.tcx.unwrap();
if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.map.local_def_id(entry_node_id);
let limits = resource_limits_from_attributes(state);
miri::run_mir_passes(tcx);
miri::eval_main(tcx, entry_def_id, limits);
miri::run_mir_passes(tcx);
let limits = resource_limits_from_attributes(state);
state.session.abort_if_errors();
if std::env::args().any(|arg| arg == "--test") {
struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'hir hir::Item) {
if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
if i.attrs.iter().any(|attr| attr.value.name == "test") {
let did = self.1.map.body_owner_def_id(body_id);
println!("running test: {}", self.1.map.def_path(did).to_string(self.1));
miri::eval_main(self.1, did, self.0);
self.2.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(limits, tcx, state));
} else {
println!("no main function found, assuming auxiliary build");
if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.map.local_def_id(entry_node_id);
miri::eval_main(tcx, entry_def_id, limits);
state.session.abort_if_errors();
} else {
println!("no main function found, assuming auxiliary build");
}
}
}
@ -147,5 +203,5 @@ fn main() {
// for auxilary builds in unit tests
args.push("-Zalways-encode-mir".to_owned());
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None);
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None);
}