From: Oliver Schneider Date: Tue, 24 Jan 2017 12:28:36 +0000 (+0100) Subject: add cargo-miri subcommand to directly interpret the main binary of a crate X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=5adb84645fe1f734acadb9a26422a791a56edef0;p=rust.git add cargo-miri subcommand to directly interpret the main binary of a crate --- diff --git a/Cargo.lock b/Cargo.lock index 94611529c5d..afe24d68472 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)" = "" +"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" diff --git a/Cargo.toml b/Cargo.toml index ada46a794cb..ba7e38bed85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs new file mode 100644 index 00000000000..71026d828a1 --- /dev/null +++ b/src/bin/cargo-miri.rs @@ -0,0 +1,177 @@ +#![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] [--] [...] + +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 manifest_path_arg = std::env::args().skip(2).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(2); + if let Some("bin") = target.kind.get(0).map(AsRef::as_ref) { + if let Err(code) = process(vec!["--bin".to_string(), target.name].into_iter().chain(args), + &dep_path) { + std::process::exit(code); + } + } else { + panic!("badly formatted cargo metadata: target::kind is an empty array"); + } + } + } 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 = 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(old_args: I, dep_path: P) -> Result<(), i32> + where P: AsRef, + I: Iterator +{ + 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)) + } +} diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 56c2e433d06..e36b9baa64b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -4,21 +4,55 @@ 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 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, + ofile: &Option, + descriptions: &rustc_errors::registry::Registry + ) -> Option<(Input, Option)> { + self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions) + } + fn late_callback( + &mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option, + ofile: &Option + ) -> 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()) { @@ -147,5 +181,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); }