From e82e96fd6b916216e866a85bbd327e4dbfad5b77 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 21 Jul 2022 13:41:24 -0700 Subject: [PATCH 01/50] Removed `InstrumentationExecutor::default: DefaultExecutor` as it does nothing an complicates logic going forward. --- dynamic_instrumentation/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dynamic_instrumentation/src/lib.rs b/dynamic_instrumentation/src/lib.rs index fa6741e1cb..fb63de414d 100644 --- a/dynamic_instrumentation/src/lib.rs +++ b/dynamic_instrumentation/src/lib.rs @@ -15,7 +15,7 @@ extern crate rustc_target; mod instrument_memory; use instrument_memory::InstrumentMemoryOps; -use cargo::core::compiler::{CompileMode, Context, DefaultExecutor, Executor, Unit}; +use cargo::core::compiler::{CompileMode, Context, Executor, Unit}; use cargo::core::{PackageId, Target, Verbosity, Workspace}; use cargo::ops; use cargo::ops::CompileOptions; @@ -132,7 +132,6 @@ pub fn instrument( rt_ws.set_target_dir(ws.target_dir()); let exec = Arc::new(InstrumentationExecutor { - default: DefaultExecutor, target_pkg: ws.current().unwrap().package_id(), rt_crate_path: Mutex::new(String::new()), building_rt: AtomicBool::new(true), @@ -151,7 +150,6 @@ pub fn instrument( INSTRUMENTER.finalize(metadata_file_path) } struct InstrumentationExecutor { - default: DefaultExecutor, target_pkg: PackageId, rt_crate_path: Mutex, building_rt: AtomicBool, @@ -166,7 +164,6 @@ impl Executor for InstrumentationExecutor { .unwrap() .to_owned(); } - self.default.init(cx, unit); } fn exec( @@ -208,7 +205,7 @@ impl Executor for InstrumentationExecutor { } } - fn force_rebuild(&self, unit: &Unit) -> bool { - self.building_rt.load(Ordering::Relaxed) || self.default.force_rebuild(unit) + fn force_rebuild(&self, _unit: &Unit) -> bool { + self.building_rt.load(Ordering::Relaxed) } } From f8ad844348cd46184780a003fa76b4beba4c70df Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:33:54 -0700 Subject: [PATCH 02/50] Added a new implementation of `c2rust-instrument` that invokes `cargo` as a subcommand, overriding `RUSTC_WRAPPER`. More specifically, instead of using `cargo` as a dependency, which is enormous and causes some compilation issues (https://github.com/immunant/c2rust/issues/488), we invoke `cargo` as a subcommand. This also has the advantage of using the correct `rustup` `cargo` wrapper so that it resolves correctly. Then we set `RUSTC_WRAPPER` to our own binary. We use `RUSTC_WRAPPER` to detect if we're being invoked as a `cargo` or `rustc` wrapper. If we're the `cargo` wrapper, we parse args using `clap` derive, determine the crate target info (that we want to instrument) using `cargo metadata` instead of the massive `cargo` dependency, and then run `cargo` as a subcommand, passing the `cargo` args as is (so all normal `cargo` invocations all work), our own executable as `$RUSTC_WRAPPER`, and the crate target info and instrumentation args serialized through `$C2RUST_INSTRUMENT_INFO`. If we're the `rustc` wrapper, we parse the instrument info, determine if we should instrument the current `rustc` command if the crate being compiled matches the crate target info passed, and based on that, either invoke `rustc` or run `RunCompiler::new(...).run()` with our `MirTransformCallbacks`, and then save the metadata to the metadata file. Note that we have to pass the `--sysroot` to `RunCompiler` as normally `rustc` looks this up relative to its executable's location, which works when the `rustup` `rustc` wrapper resolves to the toolchain-specific `rustc`, but since we're using `RunCompiler` directly and being `rustc`, we need to explicitly set the sysroot. Instead of passing `c2rust_analysis_rt` as an `--extern` and running `cargo` separately to compile it, we just add it as a normal dependency to the crate we're instrumenting. In this way it's similar to `libc`, which can be `extern`ed as it's in the sysroot, but the preferred way is to specify it as a normal dependency. --- Cargo.lock | 30 +++ analysis/test/Cargo.toml | 1 + dynamic_instrumentation/Cargo.toml | 8 + dynamic_instrumentation/src/lib.rs | 6 +- dynamic_instrumentation/src/main.rs | 351 ++++++++++++++++++++++++++++ scripts/pdg.sh | 16 +- 6 files changed, 400 insertions(+), 12 deletions(-) create mode 100644 dynamic_instrumentation/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 5e79eae05e..55c4e66be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,12 +273,20 @@ dependencies = [ "anyhow", "bincode", "c2rust-analysis-rt", + "camino", "cargo", "cargo-util", + "cargo_metadata", + "clap 3.2.8", + "color-eyre", + "env_logger", + "fs-err", "indexmap", "lazy_static", "log", "rustc-private-link", + "serde", + "serde_json", ] [[package]] @@ -332,6 +340,15 @@ dependencies = [ "syn", ] +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + [[package]] name = "cargo" version = "0.62.0" @@ -421,6 +438,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.73" diff --git a/analysis/test/Cargo.toml b/analysis/test/Cargo.toml index 5edf6636dd..48cac5dad0 100644 --- a/analysis/test/Cargo.toml +++ b/analysis/test/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] libc = "0.2" +c2rust-analysis-rt = { path = "../../analysis/runtime"} diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index 69f5686d18..b10267e688 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -12,6 +12,14 @@ cargo-util = "0.1" indexmap = "1.8" lazy_static = "1.4" log = "0.4" +env_logger = "0.9" +color-eyre = "0.6" +fs-err = "2" +clap = { version = "3.2", features = ["derive"] } +cargo_metadata = "0.15" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +camino = "1.0" [build-dependencies] rustc-private-link = { path = "../rustc-private-link" } diff --git a/dynamic_instrumentation/src/lib.rs b/dynamic_instrumentation/src/lib.rs index fb63de414d..2685756469 100644 --- a/dynamic_instrumentation/src/lib.rs +++ b/dynamic_instrumentation/src/lib.rs @@ -48,14 +48,14 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; lazy_static! { - static ref INSTRUMENTER: InstrumentMemoryOps = InstrumentMemoryOps::new(); + pub static ref INSTRUMENTER: InstrumentMemoryOps = InstrumentMemoryOps::new(); } -struct NullCallbacks; +pub struct NullCallbacks; impl rustc_driver::Callbacks for NullCallbacks {} -struct MirTransformCallbacks; +pub struct MirTransformCallbacks; impl rustc_driver::Callbacks for MirTransformCallbacks { fn config(&mut self, config: &mut rustc_interface::Config) { diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs new file mode 100644 index 0000000000..471557c5bd --- /dev/null +++ b/dynamic_instrumentation/src/main.rs @@ -0,0 +1,351 @@ +#![feature(rustc_private)] +extern crate rustc_driver; +extern crate rustc_session; +extern crate rustc_span; + +use std::{ + env, + ffi::OsString, + hash::Hash, + path::PathBuf, + process::{self, Command, ExitStatus}, + str::FromStr, +}; + +use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; +use camino::{Utf8Path, Utf8PathBuf}; +use cargo_metadata::{Metadata, MetadataCommand, Package, Target}; +use clap::Parser; +use color_eyre::eyre; +use color_eyre::eyre::eyre; +use rustc_driver::RunCompiler; +use rustc_session::config::Options; +use serde::{Deserialize, Serialize}; + +/// Instrument memory accesses for dynamic analysis. +#[derive(Debug, Parser)] +#[clap(author, version, about, long_about = None)] +struct Args { + /// Path to the metadata output file storing instrumentation locations. + #[clap(long, value_parser)] + metadata: PathBuf, + + /// Path to the `c2rust-analysis-rt` crate. + #[clap(long, value_parser)] + runtime: Utf8PathBuf, + + /// `cargo` args. + cargo_args: Vec, +} + +fn exit_with_status(status: ExitStatus) { + process::exit(status.code().unwrap_or(1)) +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +enum CrateType { + Bin, + RLib, + DyLib, + CDyLib, + StaticLib, + ProcMacro, +} + +impl FromStr for CrateType { + type Err = eyre::Report; + + fn from_str(s: &str) -> Result { + use CrateType::*; + Ok(match s { + "bin" => Bin, + // `rustc_session::config::CrateType` doesn't have a separate [`Lib`] variant. + "lib" | "rlib" => RLib, + "dylib" => DyLib, + "cdylib" => CDyLib, + "staticlib" => StaticLib, + "proc-macro" => ProcMacro, + _ => return Err(eyre!("unknown crate type: {s}")), + }) + } +} + +impl From for CrateType { + fn from(crate_type: rustc_session::config::CrateType) -> Self { + use rustc_session::config::CrateType::*; + match crate_type { + Executable => Self::Bin, + Dylib => Self::DyLib, + Rlib => Self::RLib, + Staticlib => Self::StaticLib, + Cdylib => Self::CDyLib, + ProcMacro => Self::ProcMacro, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +enum CrateEdition { + E2015, + E2018, + E2021, +} + +impl From for CrateEdition { + fn from(edition: cargo_metadata::Edition) -> Self { + use cargo_metadata::Edition::*; + match edition { + E2015 => Self::E2015, + E2018 => Self::E2018, + E2021 => Self::E2021, + _ => todo!("when `rustc_span::edition::Edition` gets a new edition, it'll cause a compile error"), + } + } +} + +impl From for CrateEdition { + fn from(edition: rustc_span::edition::Edition) -> Self { + use rustc_span::edition::Edition::*; + match edition { + Edition2015 => Self::E2015, + Edition2018 => Self::E2018, + Edition2021 => Self::E2021, + } + } +} + +/// A `crate` name, canonicalized to an identifier (i.e. `-`s are replaced with `_`). +#[derive(PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +struct CrateName { + name: String, +} + +impl CrateName { + pub fn as_str(&self) -> &str { + self.name.as_str() + } +} + +impl From<&str> for CrateName { + fn from(name: &str) -> Self { + Self { + name: name.replace('-', "_"), + } + } +} + +#[derive(Eq, Debug, Serialize, Deserialize)] +struct CrateTarget { + crate_name: CrateName, + src_path: PathBuf, + crate_types: Vec, + edition: CrateEdition, +} + +impl CrateTarget { + /// A set of stable parts of a [`CrateTarget`] that are meant to be checked for equality. + fn stable_parts(&self) -> impl Eq + Hash + '_ { + // Sometimes the [`CrateType`]s can change to `[]` depending on if tests are being built, + // so exclude that from equality checks. + ( + self.crate_name.as_str(), + self.src_path.as_path(), + self.edition, + ) + } +} + +impl PartialEq for CrateTarget { + fn eq(&self, other: &Self) -> bool { + self.stable_parts() == other.stable_parts() + } +} + +impl Hash for CrateTarget { + fn hash(&self, state: &mut H) { + self.stable_parts().hash(state); + } +} + +impl CrateTarget { + pub fn from_metadata_target(package: &Package, target: &Target) -> eyre::Result { + Ok(Self { + crate_name: package.name.as_str().into(), + src_path: target.src_path.clone().into(), + crate_types: target + .crate_types + .iter() + .map(|s| s.as_str()) + .map(CrateType::from_str) + .collect::, _>>()?, + edition: target.edition.clone().into(), + }) + } + + pub fn from_metadata_package(package: &Package) -> eyre::Result> { + package + .targets + .iter() + .map(|target| Self::from_metadata_target(package, target)) + .collect() + } + + pub fn from_session_options( + session_options: Options, + free_matches: &[String], + ) -> eyre::Result { + let src_path = match free_matches { + [src_path] => { + if src_path == "-" { + "/dev/stdin".into() + } else { + fs_err::canonicalize(src_path)? + } + } + free_matches => { + return Err(eyre!( + "`rustc` args `matches.free` is not a single source path: {free_matches:?}" + )) + } + }; + let Options { + crate_name, + crate_types, + edition, + .. + } = session_options; + let crate_name = crate_name.ok_or_else(|| eyre!("no crate_name specified by `cargo`"))?; + Ok(Self { + crate_name: crate_name.as_str().into(), + src_path, + crate_types: crate_types.into_iter().map(CrateType::from).collect(), + edition: edition.into(), + }) + } + + pub fn from_metadata(metadata: &Metadata) -> eyre::Result> { + Self::from_metadata_package( + metadata + .root_package() + .ok_or_else(|| eyre!("no root package found by `cargo`"))?, + ) + } + + pub fn from_rustc_args(at_args: &[String]) -> eyre::Result { + let args = rustc_driver::args::arg_expand_all(at_args); + let matches = rustc_driver::handle_options(&args) + .ok_or_else(|| eyre!("failed to parse `rustc` args"))?; + let session_options = rustc_session::config::build_session_options(&matches); + let crate_target = CrateTarget::from_session_options(session_options, &matches.free)?; + Ok(crate_target) + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct InstrumentInfo { + crate_targets: Vec, + metadata: PathBuf, + runtime: Utf8PathBuf, +} + +fn get_sysroot_fast() -> Option { + let sysroot = [ + env::var_os("RUSTUP_HOME")?, + "toolchains".into(), + env::var_os("RUSTUP_TOOLCHAIN")?, + ] + .into_iter() + .collect(); + Some(sysroot) +} + +fn get_sysroot_slow() -> eyre::Result { + todo!("use `rustc --print sysroot` to support non-`rustup` cases, which @fw-immunant uses") +} + +fn main() -> eyre::Result<()> { + color_eyre::install()?; + env_logger::init(); + + let rustc_wrapper_var = "RUSTC_WRAPPER"; + let instrument_info_var = "C2RUST_INSTRUMENT_INFO"; + + let own_exe = env::current_exe()?; + let own_exe = own_exe.as_path(); + + let wrapping_rustc = env::var_os(rustc_wrapper_var).as_deref() == Some(own_exe.as_os_str()); + if wrapping_rustc { + let sysroot = get_sysroot_fast() + .ok_or(()) + .or_else(|()| get_sysroot_slow())?; + let mut at_args = env::args().skip(1).collect::>(); + let crate_target = CrateTarget::from_rustc_args(&at_args)?; + let info = env::var(instrument_info_var)?; + let info = serde_json::from_str::(&info)?; + let should_instrument = info.crate_targets.contains(&crate_target); + if !should_instrument { + // We can skip a `rustup` `rustc` -> real `rustc` resolution by just invoking the real `rustc` ourselves. + // TODO(kkysen) this might not work without `rustup` + let rustc = sysroot.join("bin/rustc"); + let status = Command::new(rustc).args(at_args.iter().skip(1)).status()?; + exit_with_status(status); + } else { + // Normally, `rustc` looks up the sysroot by the location of its own binary. + // This works because the `rustc` on `$PATH` is actually `rustup`, + // and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. + // As we invoke `rustc_driver` directly here, we are `rustc`, + // and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. + // + // Note that the sysroot contains the toolchain and host target name, + // but this has no effect on cross-compiling. + // Every toolchain's `rustc` is able to itself cross-compile. + // I'm not sure why the host target needs to be in the sysroot directory name, but it is. + // + // Also note that this sysroot lookup should be done at runtime, + // not at compile-time in the `build.rs`, + // as the toolchain locations could be different + // from where this binary was compiled and where it is running + // (it could be on a different machine with a different `$RUSTUP_HOME`). + let sysroot: &Utf8Path = sysroot.as_path().try_into()?; + at_args.extend([ + "--sysroot".into(), + sysroot.as_str().into(), + // "--extern".into(), + // format!("c2rust_analysis_rt={}", info.runtime), + ]); + RunCompiler::new(&at_args, &mut MirTransformCallbacks) + .run() + .map_err(|_| eyre!("`rustc` failed"))?; + INSTRUMENTER + .finalize(&info.metadata) + .map_err(|e| eyre!(e))?; + } + } else { + let args = Args::parse(); + let Args { + metadata, + runtime, + cargo_args, + } = args; + + let cargo_metadata = MetadataCommand::new().exec()?; + let crate_targets = CrateTarget::from_metadata(&cargo_metadata)?; + let info = InstrumentInfo { + crate_targets, + metadata, + runtime, + }; + // We could binary encode this, but it's likely very short, + // so just json encode it, so it's also human readable and inspectable. + let info = serde_json::to_string(&info)?; + + let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + let status = Command::new(cargo) + .env(rustc_wrapper_var, own_exe) + .env(instrument_info_var, info) + .args(cargo_args) + .status()?; + exit_with_status(status); + } + Ok(()) +} diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 1c146983e7..6b9cd492d8 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -77,7 +77,7 @@ main() { unset RUSTC_WRAPPER local c2rust="${CWD}/${profile_dir}/c2rust" - local c2rust_instrument="${CWD}/${profile_dir}/c2rust-instrument" + local c2rust_instrument="${CWD}/${profile_dir}/c2rust-dynamic-instrumentation" local runtime="${CWD}/analysis/runtime/" local metadata="${CWD}/${test_dir}/metadata.bc" @@ -93,15 +93,13 @@ main() { local binary_path="${profile_dir}/${binary_name}" if [[ "${c2rust_instrument}" -nt "${metadata}" ]]; then - cargo clean --profile dev # always dev/debug for now + cargo clean "${profile_args[@]}" - if ! "${c2rust}" instrument \ - "${metadata}" "${runtime}" \ - -- "${profile_args[@]}" \ - 1> instrument.out.log \ - 2> instrument.err.jsonl; then - on-instrument-failure "${metadata}" - fi + "${c2rust_instrument}" \ + --metadata "${metadata}" \ + --runtime "${runtime}" \ + -- build "${profile_args[@]}" \ + 1> instrument.out.log fi export INSTRUMENT_BACKEND=log From 9361bc19735f3e25b66977224bec172d6b563828 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:34:23 -0700 Subject: [PATCH 03/50] Updated the snapshot as this rearranges basic block orders (which I think is okay). --- ...dg__tests__analysis_test_pdg_snapshot.snap | 314 +++++++++--------- 1 file changed, 157 insertions(+), 157 deletions(-) diff --git a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap index bb0b19e925..aed8bd30d4 100644 --- a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap +++ b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap @@ -77,12 +77,12 @@ g { nodes_that_need_write = [] g { - n[0]: copy _ => _46 @ bb31[6]: fn main; + n[0]: copy _ => _45 @ bb30[7]: fn main; } nodes_that_need_write = [] g { - n[0]: copy _ => _45 @ bb32[0]: fn main; + n[0]: copy _ => _44 @ bb31[0]: fn main; n[1]: copy n[0] => _2 @ bb0[0]: fn main_0; } nodes_that_need_write = [] @@ -117,18 +117,18 @@ g { n[18]: addr.store n[17] => _ @ bb4[25]: fn simple; n[19]: copy n[3] => _16 @ bb4[30]: fn simple; n[20]: copy n[19] => _2 @ bb0[0]: fn recur; - n[21]: copy n[20] => _13 @ bb8[4]: fn recur; + n[21]: copy n[20] => _12 @ bb7[10]: fn recur; n[22]: copy n[21] => _2 @ bb0[0]: fn recur; - n[23]: copy n[22] => _13 @ bb8[4]: fn recur; + n[23]: copy n[22] => _12 @ bb7[10]: fn recur; n[24]: copy n[23] => _2 @ bb0[0]: fn recur; - n[25]: copy n[24] => _13 @ bb8[4]: fn recur; + n[25]: copy n[24] => _12 @ bb7[10]: fn recur; n[26]: copy n[25] => _2 @ bb0[0]: fn recur; n[27]: copy n[26] => _8 @ bb1[3]: fn recur; n[28]: copy n[27] => _7 @ bb1[4]: fn recur; n[29]: free n[28] => _0 @ bb1[5]: fn recur; - n[30]: copy n[26] => _14 @ bb9[5]: fn recur; - n[31]: copy n[26] => _14 @ bb9[5]: fn recur; - n[32]: copy n[26] => _14 @ bb9[5]: fn recur; + n[30]: copy n[26] => _13 @ bb8[5]: fn recur; + n[31]: copy n[26] => _13 @ bb8[5]: fn recur; + n[32]: copy n[26] => _13 @ bb8[5]: fn recur; } nodes_that_need_write = [18, 17, 11, 10, 9, 8, 5, 4, 3, 2, 1, 0] @@ -190,11 +190,11 @@ g { n[15]: offset[1] n[14] => _33 @ bb11[20]: fn exercise_allocator; n[16]: field.0 n[15] => _32 @ bb13[2]: fn exercise_allocator; n[17]: addr.load n[16] => _ @ bb13[2]: fn exercise_allocator; - n[18]: copy n[1] => _43 @ bb21[7]: fn exercise_allocator; - n[19]: copy n[18] => _42 @ bb21[8]: fn exercise_allocator; + n[18]: copy n[1] => _42 @ bb20[7]: fn exercise_allocator; + n[19]: copy n[18] => _41 @ bb20[8]: fn exercise_allocator; n[20]: copy n[1] => _4 @ bb0[2]: fn reallocarray; - n[21]: copy n[20] => _1 @ bb1[3]: fn reallocarray; - n[22]: free n[19] => _41 @ bb22[2]: fn exercise_allocator; + n[21]: copy n[20] => _1 @ bb0[10]: fn reallocarray; + n[22]: free n[19] => _40 @ bb21[2]: fn exercise_allocator; } nodes_that_need_write = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] @@ -207,91 +207,91 @@ g { nodes_that_need_write = [] g { - n[0]: alloc _ => _41 @ bb22[2]: fn exercise_allocator; - n[1]: copy n[0] => _1 @ bb23[4]: fn exercise_allocator; - n[2]: copy n[1] => _48 @ bb23[8]: fn exercise_allocator; - n[3]: offset[0] n[2] => _47 @ bb23[8]: fn exercise_allocator; - n[4]: field.0 n[3] => _ @ bb24[1]: fn exercise_allocator; - n[5]: addr.store n[4] => _ @ bb24[1]: fn exercise_allocator; - n[6]: copy n[1] => _50 @ bb24[6]: fn exercise_allocator; - n[7]: offset[1] n[6] => _49 @ bb24[6]: fn exercise_allocator; - n[8]: field.0 n[7] => _ @ bb25[1]: fn exercise_allocator; - n[9]: addr.store n[8] => _ @ bb25[1]: fn exercise_allocator; - n[10]: copy n[1] => _52 @ bb25[6]: fn exercise_allocator; - n[11]: offset[2] n[10] => _51 @ bb25[6]: fn exercise_allocator; - n[12]: field.0 n[11] => _ @ bb26[1]: fn exercise_allocator; - n[13]: addr.store n[12] => _ @ bb26[1]: fn exercise_allocator; - n[14]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; - n[15]: offset[0] n[14] => _63 @ bb29[20]: fn exercise_allocator; - n[16]: field.0 n[15] => _62 @ bb31[2]: fn exercise_allocator; - n[17]: addr.load n[16] => _ @ bb31[2]: fn exercise_allocator; - n[18]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; - n[19]: offset[1] n[18] => _63 @ bb29[20]: fn exercise_allocator; - n[20]: field.0 n[19] => _62 @ bb31[2]: fn exercise_allocator; - n[21]: addr.load n[20] => _ @ bb31[2]: fn exercise_allocator; - n[22]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; - n[23]: offset[2] n[22] => _63 @ bb29[20]: fn exercise_allocator; - n[24]: field.0 n[23] => _62 @ bb31[2]: fn exercise_allocator; - n[25]: addr.load n[24] => _ @ bb31[2]: fn exercise_allocator; - n[26]: copy n[1] => _73 @ bb39[7]: fn exercise_allocator; - n[27]: copy n[26] => _72 @ bb39[8]: fn exercise_allocator; - n[28]: free n[27] => _71 @ bb39[9]: fn exercise_allocator; + n[0]: alloc _ => _40 @ bb21[2]: fn exercise_allocator; + n[1]: copy n[0] => _1 @ bb22[4]: fn exercise_allocator; + n[2]: copy n[1] => _47 @ bb22[8]: fn exercise_allocator; + n[3]: offset[0] n[2] => _46 @ bb22[8]: fn exercise_allocator; + n[4]: field.0 n[3] => _ @ bb23[1]: fn exercise_allocator; + n[5]: addr.store n[4] => _ @ bb23[1]: fn exercise_allocator; + n[6]: copy n[1] => _49 @ bb23[6]: fn exercise_allocator; + n[7]: offset[1] n[6] => _48 @ bb23[6]: fn exercise_allocator; + n[8]: field.0 n[7] => _ @ bb24[1]: fn exercise_allocator; + n[9]: addr.store n[8] => _ @ bb24[1]: fn exercise_allocator; + n[10]: copy n[1] => _51 @ bb24[6]: fn exercise_allocator; + n[11]: offset[2] n[10] => _50 @ bb24[6]: fn exercise_allocator; + n[12]: field.0 n[11] => _ @ bb25[1]: fn exercise_allocator; + n[13]: addr.store n[12] => _ @ bb25[1]: fn exercise_allocator; + n[14]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; + n[15]: offset[0] n[14] => _62 @ bb28[20]: fn exercise_allocator; + n[16]: field.0 n[15] => _61 @ bb30[2]: fn exercise_allocator; + n[17]: addr.load n[16] => _ @ bb30[2]: fn exercise_allocator; + n[18]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; + n[19]: offset[1] n[18] => _62 @ bb28[20]: fn exercise_allocator; + n[20]: field.0 n[19] => _61 @ bb30[2]: fn exercise_allocator; + n[21]: addr.load n[20] => _ @ bb30[2]: fn exercise_allocator; + n[22]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; + n[23]: offset[2] n[22] => _62 @ bb28[20]: fn exercise_allocator; + n[24]: field.0 n[23] => _61 @ bb30[2]: fn exercise_allocator; + n[25]: addr.load n[24] => _ @ bb30[2]: fn exercise_allocator; + n[26]: copy n[1] => _71 @ bb37[7]: fn exercise_allocator; + n[27]: copy n[26] => _70 @ bb37[8]: fn exercise_allocator; + n[28]: free n[27] => _69 @ bb37[9]: fn exercise_allocator; } nodes_that_need_write = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_61 _ => _60 @ bb29[7]: fn exercise_allocator; - n[1]: copy n[0] => _59 @ bb29[8]: fn exercise_allocator; - n[2]: copy n[1] => _58 @ bb29[10]: fn exercise_allocator; + n[0]: &_61 _ => _59 @ bb28[7]: fn exercise_allocator; + n[1]: copy n[0] => _58 @ bb28[8]: fn exercise_allocator; + n[2]: copy n[1] => _57 @ bb28[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; } nodes_that_need_write = [] g { - n[0]: alloc _ => _74 @ bb41[2]: fn exercise_allocator; - n[1]: copy n[0] => _1 @ bb42[3]: fn exercise_allocator; - n[2]: copy n[1] => _79 @ bb42[7]: fn exercise_allocator; - n[3]: offset[0] n[2] => _78 @ bb42[7]: fn exercise_allocator; - n[4]: field.0 n[3] => _ @ bb43[1]: fn exercise_allocator; - n[5]: addr.store n[4] => _ @ bb43[1]: fn exercise_allocator; - n[6]: copy n[1] => _81 @ bb43[6]: fn exercise_allocator; - n[7]: offset[1] n[6] => _80 @ bb43[6]: fn exercise_allocator; - n[8]: field.0 n[7] => _ @ bb44[1]: fn exercise_allocator; - n[9]: addr.store n[8] => _ @ bb44[1]: fn exercise_allocator; - n[10]: copy n[1] => _83 @ bb44[6]: fn exercise_allocator; - n[11]: offset[2] n[10] => _82 @ bb44[6]: fn exercise_allocator; - n[12]: field.0 n[11] => _ @ bb45[1]: fn exercise_allocator; - n[13]: addr.store n[12] => _ @ bb45[1]: fn exercise_allocator; - n[14]: copy n[1] => _85 @ bb45[6]: fn exercise_allocator; - n[15]: offset[3] n[14] => _84 @ bb45[6]: fn exercise_allocator; - n[16]: field.0 n[15] => _ @ bb46[1]: fn exercise_allocator; - n[17]: addr.store n[16] => _ @ bb46[1]: fn exercise_allocator; - n[18]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; - n[19]: offset[0] n[18] => _96 @ bb49[20]: fn exercise_allocator; - n[20]: field.0 n[19] => _95 @ bb51[2]: fn exercise_allocator; - n[21]: addr.load n[20] => _ @ bb51[2]: fn exercise_allocator; - n[22]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; - n[23]: offset[1] n[22] => _96 @ bb49[20]: fn exercise_allocator; - n[24]: field.0 n[23] => _95 @ bb51[2]: fn exercise_allocator; - n[25]: addr.load n[24] => _ @ bb51[2]: fn exercise_allocator; - n[26]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; - n[27]: offset[2] n[26] => _96 @ bb49[20]: fn exercise_allocator; - n[28]: field.0 n[27] => _95 @ bb51[2]: fn exercise_allocator; - n[29]: addr.load n[28] => _ @ bb51[2]: fn exercise_allocator; - n[30]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; - n[31]: offset[3] n[30] => _96 @ bb49[20]: fn exercise_allocator; - n[32]: field.0 n[31] => _95 @ bb51[2]: fn exercise_allocator; - n[33]: addr.load n[32] => _ @ bb51[2]: fn exercise_allocator; - n[34]: copy n[1] => _106 @ bb59[7]: fn exercise_allocator; - n[35]: copy n[34] => _105 @ bb59[8]: fn exercise_allocator; - n[36]: free n[35] => _104 @ bb59[9]: fn exercise_allocator; + n[0]: alloc _ => _72 @ bb39[2]: fn exercise_allocator; + n[1]: copy n[0] => _1 @ bb40[3]: fn exercise_allocator; + n[2]: copy n[1] => _77 @ bb40[7]: fn exercise_allocator; + n[3]: offset[0] n[2] => _76 @ bb40[7]: fn exercise_allocator; + n[4]: field.0 n[3] => _ @ bb41[1]: fn exercise_allocator; + n[5]: addr.store n[4] => _ @ bb41[1]: fn exercise_allocator; + n[6]: copy n[1] => _79 @ bb41[6]: fn exercise_allocator; + n[7]: offset[1] n[6] => _78 @ bb41[6]: fn exercise_allocator; + n[8]: field.0 n[7] => _ @ bb42[1]: fn exercise_allocator; + n[9]: addr.store n[8] => _ @ bb42[1]: fn exercise_allocator; + n[10]: copy n[1] => _81 @ bb42[6]: fn exercise_allocator; + n[11]: offset[2] n[10] => _80 @ bb42[6]: fn exercise_allocator; + n[12]: field.0 n[11] => _ @ bb43[1]: fn exercise_allocator; + n[13]: addr.store n[12] => _ @ bb43[1]: fn exercise_allocator; + n[14]: copy n[1] => _83 @ bb43[6]: fn exercise_allocator; + n[15]: offset[3] n[14] => _82 @ bb43[6]: fn exercise_allocator; + n[16]: field.0 n[15] => _ @ bb44[1]: fn exercise_allocator; + n[17]: addr.store n[16] => _ @ bb44[1]: fn exercise_allocator; + n[18]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; + n[19]: offset[0] n[18] => _94 @ bb47[20]: fn exercise_allocator; + n[20]: field.0 n[19] => _93 @ bb49[2]: fn exercise_allocator; + n[21]: addr.load n[20] => _ @ bb49[2]: fn exercise_allocator; + n[22]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; + n[23]: offset[1] n[22] => _94 @ bb47[20]: fn exercise_allocator; + n[24]: field.0 n[23] => _93 @ bb49[2]: fn exercise_allocator; + n[25]: addr.load n[24] => _ @ bb49[2]: fn exercise_allocator; + n[26]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; + n[27]: offset[2] n[26] => _94 @ bb47[20]: fn exercise_allocator; + n[28]: field.0 n[27] => _93 @ bb49[2]: fn exercise_allocator; + n[29]: addr.load n[28] => _ @ bb49[2]: fn exercise_allocator; + n[30]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; + n[31]: offset[3] n[30] => _94 @ bb47[20]: fn exercise_allocator; + n[32]: field.0 n[31] => _93 @ bb49[2]: fn exercise_allocator; + n[33]: addr.load n[32] => _ @ bb49[2]: fn exercise_allocator; + n[34]: copy n[1] => _103 @ bb56[7]: fn exercise_allocator; + n[35]: copy n[34] => _102 @ bb56[8]: fn exercise_allocator; + n[36]: free n[35] => _101 @ bb56[9]: fn exercise_allocator; } nodes_that_need_write = [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_94 _ => _93 @ bb49[7]: fn exercise_allocator; - n[1]: copy n[0] => _92 @ bb49[8]: fn exercise_allocator; - n[2]: copy n[1] => _91 @ bb49[10]: fn exercise_allocator; + n[0]: &_94 _ => _91 @ bb47[7]: fn exercise_allocator; + n[1]: copy n[0] => _90 @ bb47[8]: fn exercise_allocator; + n[2]: copy n[1] => _89 @ bb47[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; } nodes_that_need_write = [] @@ -589,9 +589,9 @@ g { n[13]: addr.store n[12] => _ @ bb2[16]: fn fdevent_register; n[14]: field.3 n[7] => _ @ bb2[20]: fn fdevent_register; n[15]: addr.store n[14] => _ @ bb2[20]: fn fdevent_register; - n[16]: field.4 n[7] => _ @ bb3[0]: fn fdevent_register; - n[17]: addr.store n[16] => _ @ bb3[0]: fn fdevent_register; - n[18]: copy n[7] => _0 @ bb3[3]: fn fdevent_register; + n[16]: field.4 n[7] => _ @ bb2[24]: fn fdevent_register; + n[17]: addr.store n[16] => _ @ bb2[24]: fn fdevent_register; + n[18]: copy n[7] => _0 @ bb2[27]: fn fdevent_register; n[19]: copy n[18] => _9 @ bb3[0]: fn connection_accepted; n[20]: value.store n[19] => _4.*.1 @ bb3[5]: fn connection_accepted; n[21]: value.load _ => _5 @ bb0[5]: fn connection_close; @@ -600,8 +600,8 @@ g { n[24]: copy n[23] => _1 @ bb0[0]: fn is_null; n[25]: copy n[22] => _8 @ bb2[5]: fn fdevent_fdnode_event_del; n[26]: copy n[25] => _2 @ bb0[0]: fn fdevent_fdnode_event_unsetter; - n[27]: field.4 n[26] => _8 @ bb1[3]: fn fdevent_fdnode_event_unsetter; - n[28]: addr.load n[27] => _ @ bb1[3]: fn fdevent_fdnode_event_unsetter; + n[27]: field.4 n[26] => _7 @ bb0[8]: fn fdevent_fdnode_event_unsetter; + n[28]: addr.load n[27] => _ @ bb0[8]: fn fdevent_fdnode_event_unsetter; n[29]: value.load _ => _3 @ bb1[3]: fn fdevent_unregister; n[30]: copy n[29] => _12 @ bb1[12]: fn fdevent_unregister; n[31]: ptr_to_int n[30] => _ @ bb1[12]: fn fdevent_unregister; @@ -657,22 +657,22 @@ g { n[0]: alloc _ => _1 @ bb1[2]: fn test_arg_rec; n[1]: copy n[0] => _5 @ bb2[5]: fn test_arg_rec; n[2]: copy n[1] => _2 @ bb0[0]: fn foo_rec; - n[3]: copy n[2] => _11 @ bb3[4]: fn foo_rec; + n[3]: copy n[2] => _10 @ bb1[8]: fn foo_rec; n[4]: copy n[3] => _2 @ bb0[0]: fn foo_rec; - n[5]: copy n[4] => _11 @ bb3[4]: fn foo_rec; + n[5]: copy n[4] => _10 @ bb1[8]: fn foo_rec; n[6]: copy n[5] => _2 @ bb0[0]: fn foo_rec; - n[7]: copy n[6] => _11 @ bb3[4]: fn foo_rec; + n[7]: copy n[6] => _10 @ bb1[8]: fn foo_rec; n[8]: copy n[7] => _2 @ bb0[0]: fn foo_rec; - n[9]: copy n[8] => _0 @ bb8[3]: fn foo_rec; - n[10]: copy n[9] => _7 @ bb4[0]: fn foo_rec; - n[11]: copy n[10] => _12 @ bb4[5]: fn foo_rec; - n[12]: copy n[11] => _0 @ bb4[7]: fn foo_rec; - n[13]: copy n[12] => _7 @ bb4[0]: fn foo_rec; - n[14]: copy n[13] => _12 @ bb4[5]: fn foo_rec; - n[15]: copy n[14] => _0 @ bb4[7]: fn foo_rec; - n[16]: copy n[15] => _7 @ bb4[0]: fn foo_rec; - n[17]: copy n[16] => _12 @ bb4[5]: fn foo_rec; - n[18]: copy n[17] => _0 @ bb4[7]: fn foo_rec; + n[9]: copy n[8] => _0 @ bb7[3]: fn foo_rec; + n[10]: copy n[9] => _7 @ bb3[0]: fn foo_rec; + n[11]: copy n[10] => _11 @ bb3[5]: fn foo_rec; + n[12]: copy n[11] => _0 @ bb3[7]: fn foo_rec; + n[13]: copy n[12] => _7 @ bb3[0]: fn foo_rec; + n[14]: copy n[13] => _11 @ bb3[5]: fn foo_rec; + n[15]: copy n[14] => _0 @ bb3[7]: fn foo_rec; + n[16]: copy n[15] => _7 @ bb3[0]: fn foo_rec; + n[17]: copy n[16] => _11 @ bb3[5]: fn foo_rec; + n[18]: copy n[17] => _0 @ bb3[7]: fn foo_rec; n[19]: copy n[18] => _4 @ bb3[0]: fn test_arg_rec; } nodes_that_need_write = [] @@ -680,15 +680,15 @@ nodes_that_need_write = [] g { n[0]: alloc _ => _1 @ bb1[2]: fn test_realloc_reassign; n[1]: copy n[0] => _5 @ bb2[5]: fn test_realloc_reassign; - n[2]: free n[1] => _4 @ bb4[2]: fn test_realloc_reassign; + n[2]: free n[1] => _4 @ bb3[4]: fn test_realloc_reassign; } nodes_that_need_write = [] g { - n[0]: alloc _ => _4 @ bb4[2]: fn test_realloc_reassign; - n[1]: copy n[0] => _1 @ bb5[3]: fn test_realloc_reassign; - n[2]: copy n[1] => _11 @ bb5[7]: fn test_realloc_reassign; - n[3]: free n[2] => _10 @ bb5[7]: fn test_realloc_reassign; + n[0]: alloc _ => _4 @ bb3[4]: fn test_realloc_reassign; + n[1]: copy n[0] => _1 @ bb4[3]: fn test_realloc_reassign; + n[2]: copy n[1] => _10 @ bb4[7]: fn test_realloc_reassign; + n[3]: free n[2] => _9 @ bb4[7]: fn test_realloc_reassign; } nodes_that_need_write = [] @@ -892,71 +892,71 @@ g { n[4]: offset[1] n[3] => _9 @ bb3[9]: fn insertion_sort; n[5]: addr.load n[4] => _ @ bb5[2]: fn insertion_sort; n[6]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[7]: offset[0] n[6] => _21 @ bb11[5]: fn insertion_sort; - n[8]: addr.load n[7] => _ @ bb12[2]: fn insertion_sort; - n[9]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; - n[10]: offset[1] n[9] => _46 @ bb24[13]: fn insertion_sort; - n[11]: addr.store n[10] => _ @ bb25[2]: fn insertion_sort; + n[7]: offset[0] n[6] => _21 @ bb9[16]: fn insertion_sort; + n[8]: addr.load n[7] => _ @ bb11[2]: fn insertion_sort; + n[9]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; + n[10]: offset[1] n[9] => _43 @ bb21[13]: fn insertion_sort; + n[11]: addr.store n[10] => _ @ bb22[2]: fn insertion_sort; n[12]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[13]: offset[2] n[12] => _9 @ bb3[9]: fn insertion_sort; n[14]: addr.load n[13] => _ @ bb5[2]: fn insertion_sort; n[15]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[16]: offset[1] n[15] => _21 @ bb11[5]: fn insertion_sort; - n[17]: addr.load n[16] => _ @ bb12[2]: fn insertion_sort; - n[18]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; - n[19]: offset[1] n[18] => _30 @ bb15[5]: fn insertion_sort; - n[20]: addr.load n[19] => _ @ bb16[2]: fn insertion_sort; - n[21]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; - n[22]: offset[2] n[21] => _37 @ bb16[11]: fn insertion_sort; - n[23]: addr.store n[22] => _ @ bb17[2]: fn insertion_sort; + n[16]: offset[1] n[15] => _21 @ bb9[16]: fn insertion_sort; + n[17]: addr.load n[16] => _ @ bb11[2]: fn insertion_sort; + n[18]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; + n[19]: offset[1] n[18] => _29 @ bb12[15]: fn insertion_sort; + n[20]: addr.load n[19] => _ @ bb14[2]: fn insertion_sort; + n[21]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; + n[22]: offset[2] n[21] => _35 @ bb14[11]: fn insertion_sort; + n[23]: addr.store n[22] => _ @ bb15[2]: fn insertion_sort; n[24]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[25]: offset[0] n[24] => _21 @ bb11[5]: fn insertion_sort; - n[26]: addr.load n[25] => _ @ bb12[2]: fn insertion_sort; - n[27]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; - n[28]: offset[1] n[27] => _46 @ bb24[13]: fn insertion_sort; - n[29]: addr.store n[28] => _ @ bb25[2]: fn insertion_sort; + n[25]: offset[0] n[24] => _21 @ bb9[16]: fn insertion_sort; + n[26]: addr.load n[25] => _ @ bb11[2]: fn insertion_sort; + n[27]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; + n[28]: offset[1] n[27] => _43 @ bb21[13]: fn insertion_sort; + n[29]: addr.store n[28] => _ @ bb22[2]: fn insertion_sort; n[30]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[31]: offset[3] n[30] => _9 @ bb3[9]: fn insertion_sort; n[32]: addr.load n[31] => _ @ bb5[2]: fn insertion_sort; n[33]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[34]: offset[2] n[33] => _21 @ bb11[5]: fn insertion_sort; - n[35]: addr.load n[34] => _ @ bb12[2]: fn insertion_sort; - n[36]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; - n[37]: offset[2] n[36] => _30 @ bb15[5]: fn insertion_sort; - n[38]: addr.load n[37] => _ @ bb16[2]: fn insertion_sort; - n[39]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; - n[40]: offset[3] n[39] => _37 @ bb16[11]: fn insertion_sort; - n[41]: addr.store n[40] => _ @ bb17[2]: fn insertion_sort; + n[34]: offset[2] n[33] => _21 @ bb9[16]: fn insertion_sort; + n[35]: addr.load n[34] => _ @ bb11[2]: fn insertion_sort; + n[36]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; + n[37]: offset[2] n[36] => _29 @ bb12[15]: fn insertion_sort; + n[38]: addr.load n[37] => _ @ bb14[2]: fn insertion_sort; + n[39]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; + n[40]: offset[3] n[39] => _35 @ bb14[11]: fn insertion_sort; + n[41]: addr.store n[40] => _ @ bb15[2]: fn insertion_sort; n[42]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[43]: offset[1] n[42] => _21 @ bb11[5]: fn insertion_sort; - n[44]: addr.load n[43] => _ @ bb12[2]: fn insertion_sort; - n[45]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; - n[46]: offset[1] n[45] => _30 @ bb15[5]: fn insertion_sort; - n[47]: addr.load n[46] => _ @ bb16[2]: fn insertion_sort; - n[48]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; - n[49]: offset[2] n[48] => _37 @ bb16[11]: fn insertion_sort; - n[50]: addr.store n[49] => _ @ bb17[2]: fn insertion_sort; + n[43]: offset[1] n[42] => _21 @ bb9[16]: fn insertion_sort; + n[44]: addr.load n[43] => _ @ bb11[2]: fn insertion_sort; + n[45]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; + n[46]: offset[1] n[45] => _29 @ bb12[15]: fn insertion_sort; + n[47]: addr.load n[46] => _ @ bb14[2]: fn insertion_sort; + n[48]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; + n[49]: offset[2] n[48] => _35 @ bb14[11]: fn insertion_sort; + n[50]: addr.store n[49] => _ @ bb15[2]: fn insertion_sort; n[51]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[52]: offset[0] n[51] => _21 @ bb11[5]: fn insertion_sort; - n[53]: addr.load n[52] => _ @ bb12[2]: fn insertion_sort; - n[54]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; - n[55]: offset[0] n[54] => _30 @ bb15[5]: fn insertion_sort; - n[56]: addr.load n[55] => _ @ bb16[2]: fn insertion_sort; - n[57]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; - n[58]: offset[1] n[57] => _37 @ bb16[11]: fn insertion_sort; - n[59]: addr.store n[58] => _ @ bb17[2]: fn insertion_sort; - n[60]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; - n[61]: offset[0] n[60] => _46 @ bb24[13]: fn insertion_sort; - n[62]: addr.store n[61] => _ @ bb25[2]: fn insertion_sort; + n[52]: offset[0] n[51] => _21 @ bb9[16]: fn insertion_sort; + n[53]: addr.load n[52] => _ @ bb11[2]: fn insertion_sort; + n[54]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; + n[55]: offset[0] n[54] => _29 @ bb12[15]: fn insertion_sort; + n[56]: addr.load n[55] => _ @ bb14[2]: fn insertion_sort; + n[57]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; + n[58]: offset[1] n[57] => _35 @ bb14[11]: fn insertion_sort; + n[59]: addr.store n[58] => _ @ bb15[2]: fn insertion_sort; + n[60]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; + n[61]: offset[0] n[60] => _43 @ bb21[13]: fn insertion_sort; + n[62]: addr.store n[61] => _ @ bb22[2]: fn insertion_sort; n[63]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[64]: offset[4] n[63] => _9 @ bb3[9]: fn insertion_sort; n[65]: addr.load n[64] => _ @ bb5[2]: fn insertion_sort; n[66]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[67]: offset[3] n[66] => _21 @ bb11[5]: fn insertion_sort; - n[68]: addr.load n[67] => _ @ bb12[2]: fn insertion_sort; - n[69]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; - n[70]: offset[4] n[69] => _46 @ bb24[13]: fn insertion_sort; - n[71]: addr.store n[70] => _ @ bb25[2]: fn insertion_sort; + n[67]: offset[3] n[66] => _21 @ bb9[16]: fn insertion_sort; + n[68]: addr.load n[67] => _ @ bb11[2]: fn insertion_sort; + n[69]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; + n[70]: offset[4] n[69] => _43 @ bb21[13]: fn insertion_sort; + n[71]: addr.store n[70] => _ @ bb22[2]: fn insertion_sort; } nodes_that_need_write = [71, 70, 69, 62, 61, 60, 59, 58, 57, 50, 49, 48, 41, 40, 39, 29, 28, 27, 23, 22, 21, 11, 10, 9, 2, 1, 0] From b31e7b7d08f8236c8778e894ea5582fba28b8a57 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:36:25 -0700 Subject: [PATCH 04/50] Don't need the runtime argument at all now as it's specified as a normal dependency. --- dynamic_instrumentation/src/main.rs | 9 --------- scripts/pdg.sh | 1 - 2 files changed, 10 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 471557c5bd..bab82d5f4a 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -30,10 +30,6 @@ struct Args { #[clap(long, value_parser)] metadata: PathBuf, - /// Path to the `c2rust-analysis-rt` crate. - #[clap(long, value_parser)] - runtime: Utf8PathBuf, - /// `cargo` args. cargo_args: Vec, } @@ -245,7 +241,6 @@ impl CrateTarget { struct InstrumentInfo { crate_targets: Vec, metadata: PathBuf, - runtime: Utf8PathBuf, } fn get_sysroot_fast() -> Option { @@ -310,8 +305,6 @@ fn main() -> eyre::Result<()> { at_args.extend([ "--sysroot".into(), sysroot.as_str().into(), - // "--extern".into(), - // format!("c2rust_analysis_rt={}", info.runtime), ]); RunCompiler::new(&at_args, &mut MirTransformCallbacks) .run() @@ -324,7 +317,6 @@ fn main() -> eyre::Result<()> { let args = Args::parse(); let Args { metadata, - runtime, cargo_args, } = args; @@ -333,7 +325,6 @@ fn main() -> eyre::Result<()> { let info = InstrumentInfo { crate_targets, metadata, - runtime, }; // We could binary encode this, but it's likely very short, // so just json encode it, so it's also human readable and inspectable. diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 6b9cd492d8..e65b8b3778 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -97,7 +97,6 @@ main() { "${c2rust_instrument}" \ --metadata "${metadata}" \ - --runtime "${runtime}" \ -- build "${profile_args[@]}" \ 1> instrument.out.log fi From 7ccf6d787943c2847b5a3c7d306320baff24771c Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:39:14 -0700 Subject: [PATCH 05/50] Forgot to update the profile dir in `pdg.sh` as now we can specify any `cargo` arguments, including `--release` and `--profile`. --- scripts/pdg.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index e65b8b3778..9f162b6450 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -89,7 +89,6 @@ main() { binary_name="$(command cargo metadata --format-version 1 \ | "${SCRIPT_DIR}/get-binary-names-from-cargo-metadata.mjs" default)" fi - local profile_dir="target/debug" # always dev/debug for now local binary_path="${profile_dir}/${binary_name}" if [[ "${c2rust_instrument}" -nt "${metadata}" ]]; then From 5882db5179d0dab8d23d291c4388634c08a17ee0 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:55:42 -0700 Subject: [PATCH 06/50] Now that we use `cargo` normally and include `c2rust_analysis_rt` as a normal dependency, we can delete only the main binary, forcing it to be rebuilt and re-instrumented. Most of the time building used to be in building `c2rust_analysis_rt`, and on `donna`, was ~15 seconds for `c2rust instrument`. Now it takes only ~0.5 seconds, 30x faster. Thus, we now also unconditionally instrument. Before we only did when the `c2rust-instrument` binary changed, but this missed changes to the instrumented crate. Now that it's fast enough, we just always instrument. --- ..._pdg__tests__analysis_test_pdg_snapshot.snap | 4 ++-- scripts/pdg.sh | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap index aed8bd30d4..9e98c3e659 100644 --- a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap +++ b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap @@ -240,7 +240,7 @@ g { nodes_that_need_write = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_61 _ => _59 @ bb28[7]: fn exercise_allocator; + n[0]: &_60 _ => _59 @ bb28[7]: fn exercise_allocator; n[1]: copy n[0] => _58 @ bb28[8]: fn exercise_allocator; n[2]: copy n[1] => _57 @ bb28[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; @@ -289,7 +289,7 @@ g { nodes_that_need_write = [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_94 _ => _91 @ bb47[7]: fn exercise_allocator; + n[0]: &_92 _ => _91 @ bb47[7]: fn exercise_allocator; n[1]: copy n[0] => _90 @ bb47[8]: fn exercise_allocator; n[2]: copy n[1] => _89 @ bb47[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 9f162b6450..d6d1921671 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -90,15 +90,14 @@ main() { | "${SCRIPT_DIR}/get-binary-names-from-cargo-metadata.mjs" default)" fi local binary_path="${profile_dir}/${binary_name}" - - if [[ "${c2rust_instrument}" -nt "${metadata}" ]]; then - cargo clean "${profile_args[@]}" - "${c2rust_instrument}" \ - --metadata "${metadata}" \ - -- build "${profile_args[@]}" \ - 1> instrument.out.log - fi + rm -f "${metadata}" + fd "^${binary_name//-/_}-[a-f0-9]+$" ${profile_dir}/deps/ --exec rm + + time "${c2rust_instrument}" \ + --metadata "${metadata}" \ + -- build "${profile_args[@]}" \ + 1> instrument.out.log export INSTRUMENT_BACKEND=log export INSTRUMENT_OUTPUT=log.bc @@ -108,7 +107,7 @@ main() { ) (cd pdg export RUST_BACKTRACE=full # print sources w/ color-eyre - export RUST_LOG=info + export RUST_LOG=error cargo run \ "${profile_args[@]}" \ -- \ From 54ae7ea27827d5623c7341cad670edf395a0e9f1 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 01:56:41 -0700 Subject: [PATCH 07/50] Removed unused imports and re-formatted. --- dynamic_instrumentation/src/main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index bab82d5f4a..a34678ce48 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -13,7 +13,7 @@ use std::{ }; use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; -use camino::{Utf8Path, Utf8PathBuf}; +use camino::Utf8Path; use cargo_metadata::{Metadata, MetadataCommand, Package, Target}; use clap::Parser; use color_eyre::eyre; @@ -302,10 +302,7 @@ fn main() -> eyre::Result<()> { // from where this binary was compiled and where it is running // (it could be on a different machine with a different `$RUSTUP_HOME`). let sysroot: &Utf8Path = sysroot.as_path().try_into()?; - at_args.extend([ - "--sysroot".into(), - sysroot.as_str().into(), - ]); + at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); RunCompiler::new(&at_args, &mut MirTransformCallbacks) .run() .map_err(|_| eyre!("`rustc` failed"))?; From 25fe6110d332a622ab37e0e5b3ff1df3b61889ac Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 02:18:52 -0700 Subject: [PATCH 08/50] Removed `pretty-instrument-err.mjs` as it's no longer needed since we now use `cargo` correctly and get nice error messages. --- scripts/pdg.sh | 10 --------- scripts/pretty-instrument-err.mjs | 35 ------------------------------- 2 files changed, 45 deletions(-) delete mode 100755 scripts/pretty-instrument-err.mjs diff --git a/scripts/pdg.sh b/scripts/pdg.sh index d6d1921671..47a0573a6a 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -6,16 +6,6 @@ CWD="${PWD}" SCRIPT_PATH="${0}" SCRIPT_DIR="${CWD}/$(dirname "${SCRIPT_PATH}")" -on-instrument-failure() { - local metadata="${1}" - - # delete so that we'll re-compile next time - # instead of thinking it's already done - rm -f "${metadata}" - "${SCRIPT_DIR}/pretty-instrument-err.mjs" < instrument.err.jsonl - return 1; -} - # Usage: `./pdg.sh ` # # Environment Variables: diff --git a/scripts/pretty-instrument-err.mjs b/scripts/pretty-instrument-err.mjs deleted file mode 100755 index 4ddfaadb58..0000000000 --- a/scripts/pretty-instrument-err.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node - -/** - * Consume output from `c2rust instrument` (which invokes `cargo`) - * and pretty print it. - * - * For example, `cargo` prints lots of JSONL messages, - * so we parse those and print their `rendered` fields if they have them, - * which are colored and pretty-printed already. - * - * Stack traces we leave alone. - */ - -import * as fs from "fs"; - -const [_nodePath, _scriptPath, ...args] = process.argv; -let stderr = fs.readFileSync("/dev/stdin").toString(); // jsonl -stderr = stderr.split("\n") - .map(line => { - try { - return JSON.parse(line); - } catch { - // probably a stacktrace - return { - level: "error: internal compiler error", - message: line, - rendered: line, - }; - } - }) - .filter(e => (e.level || "").includes("error")) - .map(e => e.rendered ? e.rendered : e.message) // okay if `e.rendered === ""` - .join("\n") - ; -console.error(stderr); From 11450dd40ef93d0d5a49a54fa563a3a1322e230a Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:11:15 -0700 Subject: [PATCH 09/50] Moved the metadata file and binary artifact deletion to inside the Rust binary. --- Cargo.lock | 10 +++++++ dynamic_instrumentation/Cargo.toml | 1 + dynamic_instrumentation/src/main.rs | 44 +++++++++++++++++++++++++++++ scripts/pdg.sh | 3 -- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55c4e66be8..26d055fa32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,6 +282,7 @@ dependencies = [ "env_logger", "fs-err", "indexmap", + "is_executable", "lazy_static", "log", "rustc-private-link", @@ -1154,6 +1155,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "is_executable" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +dependencies = [ + "winapi", +] + [[package]] name = "itertools" version = "0.10.3" diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index b10267e688..a815c00b3a 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -20,6 +20,7 @@ cargo_metadata = "0.15" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" camino = "1.0" +is_executable = "1.0" [build-dependencies] rustc-private-link = { path = "../rustc-private-link" } diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index a34678ce48..bc02106584 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -7,6 +7,7 @@ use std::{ env, ffi::OsString, hash::Hash, + io::ErrorKind, path::PathBuf, process::{self, Command, ExitStatus}, str::FromStr, @@ -18,6 +19,7 @@ use cargo_metadata::{Metadata, MetadataCommand, Package, Target}; use clap::Parser; use color_eyre::eyre; use color_eyre::eyre::eyre; +use is_executable::IsExecutable; use rustc_driver::RunCompiler; use rustc_session::config::Options; use serde::{Deserialize, Serialize}; @@ -323,6 +325,48 @@ fn main() -> eyre::Result<()> { crate_targets, metadata, }; + + if let Err(e) = fs_err::remove_file(&info.metadata) { + if e.kind() != ErrorKind::NotFound { + return Err(e.into()); + } + } + + // TODO(kkysen) Figure out a way to know which profile is being used + // Until then, just search them all and delete all of them. + + // TODO(kkysen) We probably have to delete binaries that have different names from the crates. + + // Delete all executables in `target/${profile}/deps/` starting with the crate name + `-`. + for profile_dir in cargo_metadata.target_directory.read_dir()? { + let profile_dir = profile_dir?; + if !profile_dir.file_type()?.is_dir() { + continue; + } + for artifact in profile_dir.path().join("deps").read_dir()? { + let artifact = artifact?; + if !artifact.file_type()?.is_file() { + continue; + } + let file_name = artifact.file_name(); + let file_name = file_name.to_str(); + for crate_target in &info.crate_targets { + let prefix = format!("{}-", crate_target.crate_name.as_str()); + // [`Path::starts_with`] only checks whole components at once, + // and `OsStr::starts_with` doesn't exist yet. + if file_name + .map(|name| name.starts_with(&prefix)) + .unwrap_or_default() + { + let artifact = artifact.path(); + if artifact.is_executable() { + fs_err::remove_file(&artifact)?; + } + } + } + } + } + // We could binary encode this, but it's likely very short, // so just json encode it, so it's also human readable and inspectable. let info = serde_json::to_string(&info)?; diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 47a0573a6a..4b15f84729 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -81,9 +81,6 @@ main() { fi local binary_path="${profile_dir}/${binary_name}" - rm -f "${metadata}" - fd "^${binary_name//-/_}-[a-f0-9]+$" ${profile_dir}/deps/ --exec rm - time "${c2rust_instrument}" \ --metadata "${metadata}" \ -- build "${profile_args[@]}" \ From bde50b685f66551b650926936b2c47174161ef7a Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:12:26 -0700 Subject: [PATCH 10/50] Use `cargo run` instead of `cargo build` now that we can specify any `cargo` args. This gets rid of another use of the binary name. --- scripts/pdg.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 4b15f84729..66ff53c37e 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -81,16 +81,16 @@ main() { fi local binary_path="${profile_dir}/${binary_name}" - time "${c2rust_instrument}" \ - --metadata "${metadata}" \ - -- build "${profile_args[@]}" \ - 1> instrument.out.log - export INSTRUMENT_BACKEND=log export INSTRUMENT_OUTPUT=log.bc export INSTRUMENT_OUTPUT_APPEND=false export METADATA_FILE="${metadata}" - "${binary_path}" "${args[@]}" + + time "${c2rust_instrument}" \ + --metadata "${metadata}" \ + -- run "${profile_args[@]}" \ + -- "${args[@]}" \ + 1> instrument.out.log ) (cd pdg export RUST_BACKTRACE=full # print sources w/ color-eyre From 0aeb0f7edffc929e6a2906488ee9cf52d966ef76 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:13:52 -0700 Subject: [PATCH 11/50] Now that all binary name uses are gone, we can delete the last `node` script: `get-binary-names-from-cargo-metadata.mjs`. --- .../get-binary-names-from-cargo-metadata.mjs | 43 ------------------- scripts/pdg.sh | 9 ---- 2 files changed, 52 deletions(-) delete mode 100755 scripts/get-binary-names-from-cargo-metadata.mjs diff --git a/scripts/get-binary-names-from-cargo-metadata.mjs b/scripts/get-binary-names-from-cargo-metadata.mjs deleted file mode 100755 index e048b33d29..0000000000 --- a/scripts/get-binary-names-from-cargo-metadata.mjs +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env node - -/** - * Parse the output of `cargo metadata --format-version 1` (on stdin) - * and print all the names of all the binaries - * produced by the current crate or workspace. - * - * There's 1 optional argument. If it's "default", - * then use the `default-run` key in `Cargo.toml`s - * and only print default target binaries. - * - * Requires a `node` that at least supports `Array.prototype.flatMap`. - * `node` 12 works. - */ - -import * as fs from "fs"; -import process from "node:process"; - -const [_nodePath, _scriptPath, ...args] = process.argv; -if (args.length > 1) { - console.error("too many arguments provided") - process.exit(1) -} -const isDefault = args[0] === "default"; - -const cargoMetadataString = fs.readFileSync("/dev/stdin"); -const cargoMetadata = JSON.parse(cargoMetadataString); -const binaryNames = cargoMetadata - .workspace_members - .map(id => cargoMetadata.packages.find(e => e.id === id)) - .flatMap(package_ => { - const useDefault = isDefault && package_.default_run; - return package_ - .targets - .filter(target => target.kind.includes("bin")) - .filter(target => !useDefault ? true : target.name === package_.default_run) - ; - }) - .map(e => e.name) - ; -for (const binaryName of binaryNames) { - console.log(binaryName); -} diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 66ff53c37e..498405244a 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -72,15 +72,6 @@ main() { local metadata="${CWD}/${test_dir}/metadata.bc" (cd "${test_dir}" - local binary_name - if [[ "${BINARY:-}" != "" ]]; then - binary_name="${BINARY}" - else - binary_name="$(command cargo metadata --format-version 1 \ - | "${SCRIPT_DIR}/get-binary-names-from-cargo-metadata.mjs" default)" - fi - local binary_path="${profile_dir}/${binary_name}" - export INSTRUMENT_BACKEND=log export INSTRUMENT_OUTPUT=log.bc export INSTRUMENT_OUTPUT_APPEND=false From 9f5dfe88a3851106dde274ec752089235b736204 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:15:16 -0700 Subject: [PATCH 12/50] Updated `pdg.sh` documentation now that `node` scripts are gone and `cargo` args restrictions aren't in place. --- scripts/pdg.sh | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 498405244a..958344a370 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -11,8 +11,6 @@ SCRIPT_DIR="${CWD}/$(dirname "${SCRIPT_PATH}")" # Environment Variables: # * `PROFILE` (default `release`): # a `cargo` profile as in `target/$PROFILE` -# * `BINARY` (default calculated by `get-binary-names-from-cargo-metadata.mjs`, require node): -# the name of the binary produced by the test crate # # Instrument and run a test crate and create its PDG. # @@ -38,16 +36,6 @@ SCRIPT_DIR="${CWD}/$(dirname "${SCRIPT_PATH}")" # Except for the `=>`-containing lines, # which are from the `latest_assignments` `HashMap`, # we want this output to remain stable. -# -# A couple of other notes: -# * `c2rust instrument` can only run the default `cargo` profile and settings right now. -# See https://github.com/immunant/c2rust/issues/448 for why. -# Thus, the instrumented binary is always in `dev`/`debug`` mode. -# The other crates are compiled in `release` mode by default, -# though that can be overridden by setting `PROFILE=debug` or another `cargo` profile. -# -# Requirements: -# * A recent node for some scripts. `node@18.2.0` works. main() { local test_dir="${1}" local args=("${@:2}") From d9b3d296a85759d206b374af52d13762f5f41626 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:16:06 -0700 Subject: [PATCH 13/50] Now that the `get-binary-names-from-cargo-metadata.mjs` `node` script is gone, we don't need to specify `BINARY=c2rust-analysis-test` in the snapshot test. --- pdg/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pdg/src/main.rs b/pdg/src/main.rs index 9acb178de5..8a85db1de1 100644 --- a/pdg/src/main.rs +++ b/pdg/src/main.rs @@ -144,7 +144,6 @@ mod tests { let dir = Path::new("analysis/test"); Command::new("scripts/pdg.sh") .arg(dir) - .env("BINARY", "c2rust-analysis-test") .status()?; let pdg = fs_err::read_to_string(dir.join("pdg.log"))?; insta::assert_display_snapshot!(pdg); From f083284be92a6281070fb1f259808e25ffb8bb81 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:19:36 -0700 Subject: [PATCH 14/50] Don't need to `unset RUSTC_WRAPPER` in `pdg.sh` anymore as we now override it. --- scripts/pdg.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 958344a370..1a63bea7c0 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -52,7 +52,6 @@ main() { cargo build "${profile_args[@]}" --features dynamic-instrumentation export RUST_BACKTRACE=1 - unset RUSTC_WRAPPER local c2rust="${CWD}/${profile_dir}/c2rust" local c2rust_instrument="${CWD}/${profile_dir}/c2rust-dynamic-instrumentation" From 95c6f08e2f13d42ed743679a757e2bc57f6561bc Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 03:20:28 -0700 Subject: [PATCH 15/50] Removed runtime args from `pdg.sh` as those are not used anymore. --- scripts/pdg.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index 1a63bea7c0..ab54baaaec 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -55,7 +55,6 @@ main() { local c2rust="${CWD}/${profile_dir}/c2rust" local c2rust_instrument="${CWD}/${profile_dir}/c2rust-dynamic-instrumentation" - local runtime="${CWD}/analysis/runtime/" local metadata="${CWD}/${test_dir}/metadata.bc" (cd "${test_dir}" From e3d221e9113073822d40a7a863fc227ce9c00776 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 11:21:30 -0700 Subject: [PATCH 16/50] Updated (and able to shorten considerably) the `pdg.sh` documentation. --- scripts/pdg.sh | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/scripts/pdg.sh b/scripts/pdg.sh index ab54baaaec..e79eff7ee7 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -14,28 +14,14 @@ SCRIPT_DIR="${CWD}/$(dirname "${SCRIPT_PATH}")" # # Instrument and run a test crate and create its PDG. # -# 1. Compile the whole `c2rust` workspace, including `c2rust instrument`. -# 2. If the `c2rust-instrument` binary has changed, -# re-instrument the test crate using `c2rust instrument`. -# The produced metadata is saved to `metadata.bc`. -# It always has to be `cargo clean`ed first, -# for not quite known reasons, which may be: -# * interactions between the default `cargo` run and the `cargo` invocation in `c2rust instrument` -# * and/or incremental compilation -# 3. Redirect `c2rust instrument` output to `instrument.out.log` and `instrument.err.jsonl`. -# These are in the test crate directory. -# If there is an error, `instrument.err.jsonl` is pretty-printed. +# 1. Compile `c2rust-dynamic-instrumentation`. +# 3. Redirect `c2rust-dynamic-instrumentation` stdout to `instrument.out.log` in the test crate directory, +# as it prints a lot of debugging info currently. # 4. Run the instrumented binary directly. -# Note that `cargo run` can't be used because -# that will recompile without instrumentation. # The `bincode`-encoded event log is written to `log.bc`. # 5. Using the `metadata.bc` metadata and the `log.bc` event log, # run `c2rust-pdg` to generate the pdg. -# The output is saved to `pdg.log` (relative to the test crate directory), -# This output is just a debug representation of the PDG. -# Except for the `=>`-containing lines, -# which are from the `latest_assignments` `HashMap`, -# we want this output to remain stable. +# The output is saved to `pdg.log` (relative to the test crate directory). main() { local test_dir="${1}" local args=("${@:2}") @@ -49,15 +35,15 @@ main() { fi local profile_args=(--profile "${profile}") - cargo build "${profile_args[@]}" --features dynamic-instrumentation - - export RUST_BACKTRACE=1 + local instrument="c2rust-dynamic-instrumentation" + cargo build "${profile_args[@]}" --bin "${instrument}" local c2rust="${CWD}/${profile_dir}/c2rust" - local c2rust_instrument="${CWD}/${profile_dir}/c2rust-dynamic-instrumentation" + local c2rust_instrument="${CWD}/${profile_dir}/${instrument}" local metadata="${CWD}/${test_dir}/metadata.bc" (cd "${test_dir}" + export RUST_BACKTRACE=1 export INSTRUMENT_BACKEND=log export INSTRUMENT_OUTPUT=log.bc export INSTRUMENT_OUTPUT_APPEND=false From b6c98aca1e19cb5e03f9b071dd0ce13256a36c82 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 12:19:41 -0700 Subject: [PATCH 17/50] Extracted a few functions from `main` to clean things up. --- dynamic_instrumentation/src/main.rs | 179 ++++++++++++++++------------ 1 file changed, 100 insertions(+), 79 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index bc02106584..9a6141f48d 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -8,7 +8,7 @@ use std::{ ffi::OsString, hash::Hash, io::ErrorKind, - path::PathBuf, + path::{Path, PathBuf}, process::{self, Command, ExitStatus}, str::FromStr, }; @@ -195,6 +195,7 @@ impl CrateTarget { let src_path = match free_matches { [src_path] => { if src_path == "-" { + // We don't actually ever read from this, so I think this is a fine translation to a real [`Path`]. "/dev/stdin".into() } else { fs_err::canonicalize(src_path)? @@ -260,6 +261,95 @@ fn get_sysroot_slow() -> eyre::Result { todo!("use `rustc --print sysroot` to support non-`rustup` cases, which @fw-immunant uses") } +fn get_sysroot() -> eyre::Result { + get_sysroot_fast() + .ok_or(()) + .or_else(|()| get_sysroot_slow()) +} + +fn passthrough_rustc(at_args: &[String], sysroot: &Path) -> eyre::Result { + // We can skip a `rustup` `rustc` -> real `rustc` resolution by just invoking the real `rustc` ourselves. + // TODO(kkysen) this might not work without `rustup` + let rustc = sysroot.join("bin/rustc"); + let status = Command::new(rustc).args(at_args.iter().skip(1)).status()?; + Ok(status) +} + +fn instrument_rustc(mut at_args: Vec, sysroot: &Path, metadata: &Path) -> eyre::Result<()> { + // Normally, `rustc` looks up the sysroot by the location of its own binary. + // This works because the `rustc` on `$PATH` is actually `rustup`, + // and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. + // As we invoke `rustc_driver` directly here, we are `rustc`, + // and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. + // + // Note that the sysroot contains the toolchain and host target name, + // but this has no effect on cross-compiling. + // Every toolchain's `rustc` is able to itself cross-compile. + // I'm not sure why the host target needs to be in the sysroot directory name, but it is. + // + // Also note that this sysroot lookup should be done at runtime, + // not at compile-time in the `build.rs`, + // as the toolchain locations could be different + // from where this binary was compiled and where it is running + // (it could be on a different machine with a different `$RUSTUP_HOME`). + let sysroot: &Utf8Path = sysroot.try_into()?; + at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); + RunCompiler::new(&at_args, &mut MirTransformCallbacks) + .run() + .map_err(|_| eyre!("`rustc` failed"))?; + INSTRUMENTER + .finalize(metadata) + .map_err(|e| eyre!(e))?; + Ok(()) +} + +/// Delete all files that we want to be regenerated +/// so that we always have fully-up-to-date, non-incremental metadata. +fn delete_metadata_and_dependencies(info: &InstrumentInfo, cargo_metadata: &Metadata) -> eyre::Result<()> { + if let Err(e) = fs_err::remove_file(&info.metadata) { + if e.kind() != ErrorKind::NotFound { + return Err(e.into()); + } + } + + // TODO(kkysen) Figure out a way to know which profile is being used + // Until then, just search them all and delete all of them. + + // TODO(kkysen) We probably have to delete binaries that have different names from the crates. + + // Delete all executables in `target/${profile}/deps/` starting with the crate name + `-`. + for profile_dir in cargo_metadata.target_directory.read_dir()? { + let profile_dir = profile_dir?; + if !profile_dir.file_type()?.is_dir() { + continue; + } + for artifact in profile_dir.path().join("deps").read_dir()? { + let artifact = artifact?; + if !artifact.file_type()?.is_file() { + continue; + } + let file_name = artifact.file_name(); + let file_name = file_name.to_str(); + for crate_target in &info.crate_targets { + let prefix = format!("{}-", crate_target.crate_name.as_str()); + // [`Path::starts_with`] only checks whole components at once, + // and `OsStr::starts_with` doesn't exist yet. + if file_name + .map(|name| name.starts_with(&prefix)) + .unwrap_or_default() + { + let artifact = artifact.path(); + if artifact.is_executable() { + fs_err::remove_file(&artifact)?; + } + } + } + } + } + + Ok(()) +} + fn main() -> eyre::Result<()> { color_eyre::install()?; env_logger::init(); @@ -268,56 +358,26 @@ fn main() -> eyre::Result<()> { let instrument_info_var = "C2RUST_INSTRUMENT_INFO"; let own_exe = env::current_exe()?; - let own_exe = own_exe.as_path(); let wrapping_rustc = env::var_os(rustc_wrapper_var).as_deref() == Some(own_exe.as_os_str()); if wrapping_rustc { - let sysroot = get_sysroot_fast() - .ok_or(()) - .or_else(|()| get_sysroot_slow())?; - let mut at_args = env::args().skip(1).collect::>(); + let sysroot = get_sysroot()?; + let at_args = env::args().skip(1).collect::>(); let crate_target = CrateTarget::from_rustc_args(&at_args)?; let info = env::var(instrument_info_var)?; let info = serde_json::from_str::(&info)?; let should_instrument = info.crate_targets.contains(&crate_target); - if !should_instrument { - // We can skip a `rustup` `rustc` -> real `rustc` resolution by just invoking the real `rustc` ourselves. - // TODO(kkysen) this might not work without `rustup` - let rustc = sysroot.join("bin/rustc"); - let status = Command::new(rustc).args(at_args.iter().skip(1)).status()?; - exit_with_status(status); + if should_instrument { + instrument_rustc(at_args, &sysroot, &info.metadata)?; } else { - // Normally, `rustc` looks up the sysroot by the location of its own binary. - // This works because the `rustc` on `$PATH` is actually `rustup`, - // and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. - // As we invoke `rustc_driver` directly here, we are `rustc`, - // and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. - // - // Note that the sysroot contains the toolchain and host target name, - // but this has no effect on cross-compiling. - // Every toolchain's `rustc` is able to itself cross-compile. - // I'm not sure why the host target needs to be in the sysroot directory name, but it is. - // - // Also note that this sysroot lookup should be done at runtime, - // not at compile-time in the `build.rs`, - // as the toolchain locations could be different - // from where this binary was compiled and where it is running - // (it could be on a different machine with a different `$RUSTUP_HOME`). - let sysroot: &Utf8Path = sysroot.as_path().try_into()?; - at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); - RunCompiler::new(&at_args, &mut MirTransformCallbacks) - .run() - .map_err(|_| eyre!("`rustc` failed"))?; - INSTRUMENTER - .finalize(&info.metadata) - .map_err(|e| eyre!(e))?; + let status = passthrough_rustc(&at_args, &sysroot)?; + exit_with_status(status); } } else { - let args = Args::parse(); let Args { metadata, cargo_args, - } = args; + } = Args::parse(); let cargo_metadata = MetadataCommand::new().exec()?; let crate_targets = CrateTarget::from_metadata(&cargo_metadata)?; @@ -326,46 +386,7 @@ fn main() -> eyre::Result<()> { metadata, }; - if let Err(e) = fs_err::remove_file(&info.metadata) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - // TODO(kkysen) Figure out a way to know which profile is being used - // Until then, just search them all and delete all of them. - - // TODO(kkysen) We probably have to delete binaries that have different names from the crates. - - // Delete all executables in `target/${profile}/deps/` starting with the crate name + `-`. - for profile_dir in cargo_metadata.target_directory.read_dir()? { - let profile_dir = profile_dir?; - if !profile_dir.file_type()?.is_dir() { - continue; - } - for artifact in profile_dir.path().join("deps").read_dir()? { - let artifact = artifact?; - if !artifact.file_type()?.is_file() { - continue; - } - let file_name = artifact.file_name(); - let file_name = file_name.to_str(); - for crate_target in &info.crate_targets { - let prefix = format!("{}-", crate_target.crate_name.as_str()); - // [`Path::starts_with`] only checks whole components at once, - // and `OsStr::starts_with` doesn't exist yet. - if file_name - .map(|name| name.starts_with(&prefix)) - .unwrap_or_default() - { - let artifact = artifact.path(); - if artifact.is_executable() { - fs_err::remove_file(&artifact)?; - } - } - } - } - } + delete_metadata_and_dependencies(&info, &cargo_metadata)?; // We could binary encode this, but it's likely very short, // so just json encode it, so it's also human readable and inspectable. @@ -373,7 +394,7 @@ fn main() -> eyre::Result<()> { let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); let status = Command::new(cargo) - .env(rustc_wrapper_var, own_exe) + .env(rustc_wrapper_var, &own_exe) .env(instrument_info_var, info) .args(cargo_args) .status()?; From baf5a8d617da155b6724aa4cf31404f7368e4ebc Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 14:35:12 -0700 Subject: [PATCH 18/50] Formatted. --- dynamic_instrumentation/src/main.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 9a6141f48d..633d7b0419 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -297,15 +297,16 @@ fn instrument_rustc(mut at_args: Vec, sysroot: &Path, metadata: &Path) - RunCompiler::new(&at_args, &mut MirTransformCallbacks) .run() .map_err(|_| eyre!("`rustc` failed"))?; - INSTRUMENTER - .finalize(metadata) - .map_err(|e| eyre!(e))?; + INSTRUMENTER.finalize(metadata).map_err(|e| eyre!(e))?; Ok(()) } /// Delete all files that we want to be regenerated /// so that we always have fully-up-to-date, non-incremental metadata. -fn delete_metadata_and_dependencies(info: &InstrumentInfo, cargo_metadata: &Metadata) -> eyre::Result<()> { +fn delete_metadata_and_dependencies( + info: &InstrumentInfo, + cargo_metadata: &Metadata, +) -> eyre::Result<()> { if let Err(e) = fs_err::remove_file(&info.metadata) { if e.kind() != ErrorKind::NotFound { return Err(e.into()); @@ -394,9 +395,9 @@ fn main() -> eyre::Result<()> { let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); let status = Command::new(cargo) + .args(cargo_args) .env(rustc_wrapper_var, &own_exe) .env(instrument_info_var, info) - .args(cargo_args) .status()?; exit_with_status(status); } From 0a46ad82bb4b4fc0a237ad33ddde3adc6f156bc9 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 15:24:14 -0700 Subject: [PATCH 19/50] Updated the snapshot back to a `debug` not `release` build, so there should be no diff now. --- pdg/src/main.rs | 1 + ...dg__tests__analysis_test_pdg_snapshot.snap | 314 +++++++++--------- 2 files changed, 158 insertions(+), 157 deletions(-) diff --git a/pdg/src/main.rs b/pdg/src/main.rs index 8a85db1de1..c007c9c6b7 100644 --- a/pdg/src/main.rs +++ b/pdg/src/main.rs @@ -144,6 +144,7 @@ mod tests { let dir = Path::new("analysis/test"); Command::new("scripts/pdg.sh") .arg(dir) + .env("PROFILE", "debug") .status()?; let pdg = fs_err::read_to_string(dir.join("pdg.log"))?; insta::assert_display_snapshot!(pdg); diff --git a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap index 6dcda90d69..334ece0eab 100644 --- a/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap +++ b/pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap @@ -74,12 +74,12 @@ g { nodes_that_need_write = [] g { - n[0]: &_1 _ => _45 @ bb30[7]: fn main; + n[0]: &_1 _ => _46 @ bb31[6]: fn main; } nodes_that_need_write = [] g { - n[0]: copy _ => _44 @ bb31[0]: fn main; + n[0]: copy _ => _45 @ bb32[0]: fn main; n[1]: copy n[0] => _2 @ bb0[0]: fn main_0; } nodes_that_need_write = [] @@ -114,18 +114,18 @@ g { n[18]: addr.store n[17] => _ @ bb4[25]: fn simple; n[19]: copy n[3] => _16 @ bb4[30]: fn simple; n[20]: copy n[19] => _2 @ bb0[0]: fn recur; - n[21]: copy n[20] => _12 @ bb7[10]: fn recur; + n[21]: copy n[20] => _13 @ bb8[4]: fn recur; n[22]: copy n[21] => _2 @ bb0[0]: fn recur; - n[23]: copy n[22] => _12 @ bb7[10]: fn recur; + n[23]: copy n[22] => _13 @ bb8[4]: fn recur; n[24]: copy n[23] => _2 @ bb0[0]: fn recur; - n[25]: copy n[24] => _12 @ bb7[10]: fn recur; + n[25]: copy n[24] => _13 @ bb8[4]: fn recur; n[26]: copy n[25] => _2 @ bb0[0]: fn recur; n[27]: copy n[26] => _8 @ bb1[3]: fn recur; n[28]: copy n[27] => _7 @ bb1[4]: fn recur; n[29]: free n[28] => _0 @ bb1[5]: fn recur; - n[30]: copy n[26] => _13 @ bb8[5]: fn recur; - n[31]: copy n[26] => _13 @ bb8[5]: fn recur; - n[32]: copy n[26] => _13 @ bb8[5]: fn recur; + n[30]: copy n[26] => _14 @ bb9[5]: fn recur; + n[31]: copy n[26] => _14 @ bb9[5]: fn recur; + n[32]: copy n[26] => _14 @ bb9[5]: fn recur; n[33]: addr.load n[1] => _ @ bb5[3]: fn simple; n[34]: addr.store n[3] => _ @ bb5[7]: fn simple; } @@ -187,11 +187,11 @@ g { n[15]: offset[1] n[14] => _33 @ bb11[20]: fn exercise_allocator; n[16]: field.0 n[15] => _32 @ bb13[2]: fn exercise_allocator; n[17]: addr.load n[16] => _ @ bb13[2]: fn exercise_allocator; - n[18]: copy n[1] => _42 @ bb20[7]: fn exercise_allocator; - n[19]: copy n[18] => _41 @ bb20[8]: fn exercise_allocator; + n[18]: copy n[1] => _43 @ bb21[7]: fn exercise_allocator; + n[19]: copy n[18] => _42 @ bb21[8]: fn exercise_allocator; n[20]: copy n[1] => _4 @ bb0[2]: fn reallocarray; - n[21]: copy n[20] => _1 @ bb0[10]: fn reallocarray; - n[22]: free n[19] => _40 @ bb21[2]: fn exercise_allocator; + n[21]: copy n[20] => _1 @ bb1[3]: fn reallocarray; + n[22]: free n[19] => _41 @ bb22[2]: fn exercise_allocator; } nodes_that_need_write = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] @@ -204,91 +204,91 @@ g { nodes_that_need_write = [] g { - n[0]: alloc _ => _40 @ bb21[2]: fn exercise_allocator; - n[1]: copy n[0] => _1 @ bb22[4]: fn exercise_allocator; - n[2]: copy n[1] => _47 @ bb22[8]: fn exercise_allocator; - n[3]: offset[0] n[2] => _46 @ bb22[8]: fn exercise_allocator; - n[4]: field.0 n[3] => _ @ bb23[1]: fn exercise_allocator; - n[5]: addr.store n[4] => _ @ bb23[1]: fn exercise_allocator; - n[6]: copy n[1] => _49 @ bb23[6]: fn exercise_allocator; - n[7]: offset[1] n[6] => _48 @ bb23[6]: fn exercise_allocator; - n[8]: field.0 n[7] => _ @ bb24[1]: fn exercise_allocator; - n[9]: addr.store n[8] => _ @ bb24[1]: fn exercise_allocator; - n[10]: copy n[1] => _51 @ bb24[6]: fn exercise_allocator; - n[11]: offset[2] n[10] => _50 @ bb24[6]: fn exercise_allocator; - n[12]: field.0 n[11] => _ @ bb25[1]: fn exercise_allocator; - n[13]: addr.store n[12] => _ @ bb25[1]: fn exercise_allocator; - n[14]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; - n[15]: offset[0] n[14] => _62 @ bb28[20]: fn exercise_allocator; - n[16]: field.0 n[15] => _61 @ bb30[2]: fn exercise_allocator; - n[17]: addr.load n[16] => _ @ bb30[2]: fn exercise_allocator; - n[18]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; - n[19]: offset[1] n[18] => _62 @ bb28[20]: fn exercise_allocator; - n[20]: field.0 n[19] => _61 @ bb30[2]: fn exercise_allocator; - n[21]: addr.load n[20] => _ @ bb30[2]: fn exercise_allocator; - n[22]: copy n[1] => _63 @ bb28[15]: fn exercise_allocator; - n[23]: offset[2] n[22] => _62 @ bb28[20]: fn exercise_allocator; - n[24]: field.0 n[23] => _61 @ bb30[2]: fn exercise_allocator; - n[25]: addr.load n[24] => _ @ bb30[2]: fn exercise_allocator; - n[26]: copy n[1] => _71 @ bb37[7]: fn exercise_allocator; - n[27]: copy n[26] => _70 @ bb37[8]: fn exercise_allocator; - n[28]: free n[27] => _69 @ bb37[9]: fn exercise_allocator; + n[0]: alloc _ => _41 @ bb22[2]: fn exercise_allocator; + n[1]: copy n[0] => _1 @ bb23[4]: fn exercise_allocator; + n[2]: copy n[1] => _48 @ bb23[8]: fn exercise_allocator; + n[3]: offset[0] n[2] => _47 @ bb23[8]: fn exercise_allocator; + n[4]: field.0 n[3] => _ @ bb24[1]: fn exercise_allocator; + n[5]: addr.store n[4] => _ @ bb24[1]: fn exercise_allocator; + n[6]: copy n[1] => _50 @ bb24[6]: fn exercise_allocator; + n[7]: offset[1] n[6] => _49 @ bb24[6]: fn exercise_allocator; + n[8]: field.0 n[7] => _ @ bb25[1]: fn exercise_allocator; + n[9]: addr.store n[8] => _ @ bb25[1]: fn exercise_allocator; + n[10]: copy n[1] => _52 @ bb25[6]: fn exercise_allocator; + n[11]: offset[2] n[10] => _51 @ bb25[6]: fn exercise_allocator; + n[12]: field.0 n[11] => _ @ bb26[1]: fn exercise_allocator; + n[13]: addr.store n[12] => _ @ bb26[1]: fn exercise_allocator; + n[14]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; + n[15]: offset[0] n[14] => _63 @ bb29[20]: fn exercise_allocator; + n[16]: field.0 n[15] => _62 @ bb31[2]: fn exercise_allocator; + n[17]: addr.load n[16] => _ @ bb31[2]: fn exercise_allocator; + n[18]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; + n[19]: offset[1] n[18] => _63 @ bb29[20]: fn exercise_allocator; + n[20]: field.0 n[19] => _62 @ bb31[2]: fn exercise_allocator; + n[21]: addr.load n[20] => _ @ bb31[2]: fn exercise_allocator; + n[22]: copy n[1] => _64 @ bb29[15]: fn exercise_allocator; + n[23]: offset[2] n[22] => _63 @ bb29[20]: fn exercise_allocator; + n[24]: field.0 n[23] => _62 @ bb31[2]: fn exercise_allocator; + n[25]: addr.load n[24] => _ @ bb31[2]: fn exercise_allocator; + n[26]: copy n[1] => _73 @ bb39[7]: fn exercise_allocator; + n[27]: copy n[26] => _72 @ bb39[8]: fn exercise_allocator; + n[28]: free n[27] => _71 @ bb39[9]: fn exercise_allocator; } nodes_that_need_write = [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_60 _ => _59 @ bb28[7]: fn exercise_allocator; - n[1]: copy n[0] => _58 @ bb28[8]: fn exercise_allocator; - n[2]: copy n[1] => _57 @ bb28[10]: fn exercise_allocator; + n[0]: &_61 _ => _60 @ bb29[7]: fn exercise_allocator; + n[1]: copy n[0] => _59 @ bb29[8]: fn exercise_allocator; + n[2]: copy n[1] => _58 @ bb29[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; } nodes_that_need_write = [] g { - n[0]: alloc _ => _72 @ bb39[2]: fn exercise_allocator; - n[1]: copy n[0] => _1 @ bb40[3]: fn exercise_allocator; - n[2]: copy n[1] => _77 @ bb40[7]: fn exercise_allocator; - n[3]: offset[0] n[2] => _76 @ bb40[7]: fn exercise_allocator; - n[4]: field.0 n[3] => _ @ bb41[1]: fn exercise_allocator; - n[5]: addr.store n[4] => _ @ bb41[1]: fn exercise_allocator; - n[6]: copy n[1] => _79 @ bb41[6]: fn exercise_allocator; - n[7]: offset[1] n[6] => _78 @ bb41[6]: fn exercise_allocator; - n[8]: field.0 n[7] => _ @ bb42[1]: fn exercise_allocator; - n[9]: addr.store n[8] => _ @ bb42[1]: fn exercise_allocator; - n[10]: copy n[1] => _81 @ bb42[6]: fn exercise_allocator; - n[11]: offset[2] n[10] => _80 @ bb42[6]: fn exercise_allocator; - n[12]: field.0 n[11] => _ @ bb43[1]: fn exercise_allocator; - n[13]: addr.store n[12] => _ @ bb43[1]: fn exercise_allocator; - n[14]: copy n[1] => _83 @ bb43[6]: fn exercise_allocator; - n[15]: offset[3] n[14] => _82 @ bb43[6]: fn exercise_allocator; - n[16]: field.0 n[15] => _ @ bb44[1]: fn exercise_allocator; - n[17]: addr.store n[16] => _ @ bb44[1]: fn exercise_allocator; - n[18]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; - n[19]: offset[0] n[18] => _94 @ bb47[20]: fn exercise_allocator; - n[20]: field.0 n[19] => _93 @ bb49[2]: fn exercise_allocator; - n[21]: addr.load n[20] => _ @ bb49[2]: fn exercise_allocator; - n[22]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; - n[23]: offset[1] n[22] => _94 @ bb47[20]: fn exercise_allocator; - n[24]: field.0 n[23] => _93 @ bb49[2]: fn exercise_allocator; - n[25]: addr.load n[24] => _ @ bb49[2]: fn exercise_allocator; - n[26]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; - n[27]: offset[2] n[26] => _94 @ bb47[20]: fn exercise_allocator; - n[28]: field.0 n[27] => _93 @ bb49[2]: fn exercise_allocator; - n[29]: addr.load n[28] => _ @ bb49[2]: fn exercise_allocator; - n[30]: copy n[1] => _95 @ bb47[15]: fn exercise_allocator; - n[31]: offset[3] n[30] => _94 @ bb47[20]: fn exercise_allocator; - n[32]: field.0 n[31] => _93 @ bb49[2]: fn exercise_allocator; - n[33]: addr.load n[32] => _ @ bb49[2]: fn exercise_allocator; - n[34]: copy n[1] => _103 @ bb56[7]: fn exercise_allocator; - n[35]: copy n[34] => _102 @ bb56[8]: fn exercise_allocator; - n[36]: free n[35] => _101 @ bb56[9]: fn exercise_allocator; + n[0]: alloc _ => _74 @ bb41[2]: fn exercise_allocator; + n[1]: copy n[0] => _1 @ bb42[3]: fn exercise_allocator; + n[2]: copy n[1] => _79 @ bb42[7]: fn exercise_allocator; + n[3]: offset[0] n[2] => _78 @ bb42[7]: fn exercise_allocator; + n[4]: field.0 n[3] => _ @ bb43[1]: fn exercise_allocator; + n[5]: addr.store n[4] => _ @ bb43[1]: fn exercise_allocator; + n[6]: copy n[1] => _81 @ bb43[6]: fn exercise_allocator; + n[7]: offset[1] n[6] => _80 @ bb43[6]: fn exercise_allocator; + n[8]: field.0 n[7] => _ @ bb44[1]: fn exercise_allocator; + n[9]: addr.store n[8] => _ @ bb44[1]: fn exercise_allocator; + n[10]: copy n[1] => _83 @ bb44[6]: fn exercise_allocator; + n[11]: offset[2] n[10] => _82 @ bb44[6]: fn exercise_allocator; + n[12]: field.0 n[11] => _ @ bb45[1]: fn exercise_allocator; + n[13]: addr.store n[12] => _ @ bb45[1]: fn exercise_allocator; + n[14]: copy n[1] => _85 @ bb45[6]: fn exercise_allocator; + n[15]: offset[3] n[14] => _84 @ bb45[6]: fn exercise_allocator; + n[16]: field.0 n[15] => _ @ bb46[1]: fn exercise_allocator; + n[17]: addr.store n[16] => _ @ bb46[1]: fn exercise_allocator; + n[18]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; + n[19]: offset[0] n[18] => _96 @ bb49[20]: fn exercise_allocator; + n[20]: field.0 n[19] => _95 @ bb51[2]: fn exercise_allocator; + n[21]: addr.load n[20] => _ @ bb51[2]: fn exercise_allocator; + n[22]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; + n[23]: offset[1] n[22] => _96 @ bb49[20]: fn exercise_allocator; + n[24]: field.0 n[23] => _95 @ bb51[2]: fn exercise_allocator; + n[25]: addr.load n[24] => _ @ bb51[2]: fn exercise_allocator; + n[26]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; + n[27]: offset[2] n[26] => _96 @ bb49[20]: fn exercise_allocator; + n[28]: field.0 n[27] => _95 @ bb51[2]: fn exercise_allocator; + n[29]: addr.load n[28] => _ @ bb51[2]: fn exercise_allocator; + n[30]: copy n[1] => _97 @ bb49[15]: fn exercise_allocator; + n[31]: offset[3] n[30] => _96 @ bb49[20]: fn exercise_allocator; + n[32]: field.0 n[31] => _95 @ bb51[2]: fn exercise_allocator; + n[33]: addr.load n[32] => _ @ bb51[2]: fn exercise_allocator; + n[34]: copy n[1] => _106 @ bb59[7]: fn exercise_allocator; + n[35]: copy n[34] => _105 @ bb59[8]: fn exercise_allocator; + n[36]: free n[35] => _104 @ bb59[9]: fn exercise_allocator; } nodes_that_need_write = [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] g { - n[0]: &_92 _ => _91 @ bb47[7]: fn exercise_allocator; - n[1]: copy n[0] => _90 @ bb47[8]: fn exercise_allocator; - n[2]: copy n[1] => _89 @ bb47[10]: fn exercise_allocator; + n[0]: &_94 _ => _93 @ bb49[7]: fn exercise_allocator; + n[1]: copy n[0] => _92 @ bb49[8]: fn exercise_allocator; + n[2]: copy n[1] => _91 @ bb49[10]: fn exercise_allocator; n[3]: copy n[2] => _1 @ bb0[0]: fn printf; } nodes_that_need_write = [] @@ -598,9 +598,9 @@ g { n[13]: addr.store n[12] => _ @ bb2[16]: fn fdevent_register; n[14]: field.3 n[7] => _ @ bb2[20]: fn fdevent_register; n[15]: addr.store n[14] => _ @ bb2[20]: fn fdevent_register; - n[16]: field.4 n[7] => _ @ bb2[24]: fn fdevent_register; - n[17]: addr.store n[16] => _ @ bb2[24]: fn fdevent_register; - n[18]: copy n[7] => _0 @ bb2[27]: fn fdevent_register; + n[16]: field.4 n[7] => _ @ bb3[0]: fn fdevent_register; + n[17]: addr.store n[16] => _ @ bb3[0]: fn fdevent_register; + n[18]: copy n[7] => _0 @ bb3[3]: fn fdevent_register; n[19]: copy n[18] => _9 @ bb3[0]: fn connection_accepted; n[20]: value.store n[19] => _4.*.1 @ bb3[5]: fn connection_accepted; n[21]: value.load _ => _5 @ bb0[5]: fn connection_close; @@ -609,8 +609,8 @@ g { n[24]: copy n[23] => _1 @ bb0[0]: fn is_null; n[25]: copy n[22] => _8 @ bb2[5]: fn fdevent_fdnode_event_del; n[26]: copy n[25] => _2 @ bb0[0]: fn fdevent_fdnode_event_unsetter; - n[27]: field.4 n[26] => _7 @ bb0[8]: fn fdevent_fdnode_event_unsetter; - n[28]: addr.load n[27] => _ @ bb0[8]: fn fdevent_fdnode_event_unsetter; + n[27]: field.4 n[26] => _8 @ bb1[3]: fn fdevent_fdnode_event_unsetter; + n[28]: addr.load n[27] => _ @ bb1[3]: fn fdevent_fdnode_event_unsetter; n[29]: value.load _ => _3 @ bb1[3]: fn fdevent_unregister; n[30]: copy n[29] => _12 @ bb1[12]: fn fdevent_unregister; n[31]: ptr_to_int n[30] => _ @ bb1[12]: fn fdevent_unregister; @@ -661,22 +661,22 @@ g { n[0]: alloc _ => _1 @ bb1[2]: fn test_arg_rec; n[1]: copy n[0] => _5 @ bb2[5]: fn test_arg_rec; n[2]: copy n[1] => _2 @ bb0[0]: fn foo_rec; - n[3]: copy n[2] => _10 @ bb1[8]: fn foo_rec; + n[3]: copy n[2] => _11 @ bb3[4]: fn foo_rec; n[4]: copy n[3] => _2 @ bb0[0]: fn foo_rec; - n[5]: copy n[4] => _10 @ bb1[8]: fn foo_rec; + n[5]: copy n[4] => _11 @ bb3[4]: fn foo_rec; n[6]: copy n[5] => _2 @ bb0[0]: fn foo_rec; - n[7]: copy n[6] => _10 @ bb1[8]: fn foo_rec; + n[7]: copy n[6] => _11 @ bb3[4]: fn foo_rec; n[8]: copy n[7] => _2 @ bb0[0]: fn foo_rec; - n[9]: copy n[8] => _0 @ bb7[3]: fn foo_rec; - n[10]: copy n[9] => _7 @ bb3[0]: fn foo_rec; - n[11]: copy n[10] => _11 @ bb3[5]: fn foo_rec; - n[12]: copy n[11] => _0 @ bb3[7]: fn foo_rec; - n[13]: copy n[12] => _7 @ bb3[0]: fn foo_rec; - n[14]: copy n[13] => _11 @ bb3[5]: fn foo_rec; - n[15]: copy n[14] => _0 @ bb3[7]: fn foo_rec; - n[16]: copy n[15] => _7 @ bb3[0]: fn foo_rec; - n[17]: copy n[16] => _11 @ bb3[5]: fn foo_rec; - n[18]: copy n[17] => _0 @ bb3[7]: fn foo_rec; + n[9]: copy n[8] => _0 @ bb8[3]: fn foo_rec; + n[10]: copy n[9] => _7 @ bb4[0]: fn foo_rec; + n[11]: copy n[10] => _12 @ bb4[5]: fn foo_rec; + n[12]: copy n[11] => _0 @ bb4[7]: fn foo_rec; + n[13]: copy n[12] => _7 @ bb4[0]: fn foo_rec; + n[14]: copy n[13] => _12 @ bb4[5]: fn foo_rec; + n[15]: copy n[14] => _0 @ bb4[7]: fn foo_rec; + n[16]: copy n[15] => _7 @ bb4[0]: fn foo_rec; + n[17]: copy n[16] => _12 @ bb4[5]: fn foo_rec; + n[18]: copy n[17] => _0 @ bb4[7]: fn foo_rec; n[19]: copy n[18] => _4 @ bb3[0]: fn test_arg_rec; } nodes_that_need_write = [] @@ -721,15 +721,15 @@ nodes_that_need_write = [] g { n[0]: alloc _ => _1 @ bb1[2]: fn test_realloc_reassign; n[1]: copy n[0] => _5 @ bb2[5]: fn test_realloc_reassign; - n[2]: free n[1] => _4 @ bb3[4]: fn test_realloc_reassign; + n[2]: free n[1] => _4 @ bb4[2]: fn test_realloc_reassign; } nodes_that_need_write = [] g { - n[0]: alloc _ => _4 @ bb3[4]: fn test_realloc_reassign; - n[1]: copy n[0] => _1 @ bb4[3]: fn test_realloc_reassign; - n[2]: copy n[1] => _10 @ bb4[7]: fn test_realloc_reassign; - n[3]: free n[2] => _9 @ bb4[7]: fn test_realloc_reassign; + n[0]: alloc _ => _4 @ bb4[2]: fn test_realloc_reassign; + n[1]: copy n[0] => _1 @ bb5[3]: fn test_realloc_reassign; + n[2]: copy n[1] => _11 @ bb5[7]: fn test_realloc_reassign; + n[3]: free n[2] => _10 @ bb5[7]: fn test_realloc_reassign; } nodes_that_need_write = [] @@ -931,71 +931,71 @@ g { n[4]: offset[1] n[3] => _9 @ bb3[9]: fn insertion_sort; n[5]: addr.load n[4] => _ @ bb5[2]: fn insertion_sort; n[6]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[7]: offset[0] n[6] => _21 @ bb9[16]: fn insertion_sort; - n[8]: addr.load n[7] => _ @ bb11[2]: fn insertion_sort; - n[9]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; - n[10]: offset[1] n[9] => _43 @ bb21[13]: fn insertion_sort; - n[11]: addr.store n[10] => _ @ bb22[2]: fn insertion_sort; + n[7]: offset[0] n[6] => _21 @ bb11[5]: fn insertion_sort; + n[8]: addr.load n[7] => _ @ bb12[2]: fn insertion_sort; + n[9]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; + n[10]: offset[1] n[9] => _46 @ bb24[13]: fn insertion_sort; + n[11]: addr.store n[10] => _ @ bb25[2]: fn insertion_sort; n[12]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[13]: offset[2] n[12] => _9 @ bb3[9]: fn insertion_sort; n[14]: addr.load n[13] => _ @ bb5[2]: fn insertion_sort; n[15]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[16]: offset[1] n[15] => _21 @ bb9[16]: fn insertion_sort; - n[17]: addr.load n[16] => _ @ bb11[2]: fn insertion_sort; - n[18]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; - n[19]: offset[1] n[18] => _29 @ bb12[15]: fn insertion_sort; - n[20]: addr.load n[19] => _ @ bb14[2]: fn insertion_sort; - n[21]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; - n[22]: offset[2] n[21] => _35 @ bb14[11]: fn insertion_sort; - n[23]: addr.store n[22] => _ @ bb15[2]: fn insertion_sort; + n[16]: offset[1] n[15] => _21 @ bb11[5]: fn insertion_sort; + n[17]: addr.load n[16] => _ @ bb12[2]: fn insertion_sort; + n[18]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; + n[19]: offset[1] n[18] => _30 @ bb15[5]: fn insertion_sort; + n[20]: addr.load n[19] => _ @ bb16[2]: fn insertion_sort; + n[21]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; + n[22]: offset[2] n[21] => _37 @ bb16[11]: fn insertion_sort; + n[23]: addr.store n[22] => _ @ bb17[2]: fn insertion_sort; n[24]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[25]: offset[0] n[24] => _21 @ bb9[16]: fn insertion_sort; - n[26]: addr.load n[25] => _ @ bb11[2]: fn insertion_sort; - n[27]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; - n[28]: offset[1] n[27] => _43 @ bb21[13]: fn insertion_sort; - n[29]: addr.store n[28] => _ @ bb22[2]: fn insertion_sort; + n[25]: offset[0] n[24] => _21 @ bb11[5]: fn insertion_sort; + n[26]: addr.load n[25] => _ @ bb12[2]: fn insertion_sort; + n[27]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; + n[28]: offset[1] n[27] => _46 @ bb24[13]: fn insertion_sort; + n[29]: addr.store n[28] => _ @ bb25[2]: fn insertion_sort; n[30]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[31]: offset[3] n[30] => _9 @ bb3[9]: fn insertion_sort; n[32]: addr.load n[31] => _ @ bb5[2]: fn insertion_sort; n[33]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[34]: offset[2] n[33] => _21 @ bb9[16]: fn insertion_sort; - n[35]: addr.load n[34] => _ @ bb11[2]: fn insertion_sort; - n[36]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; - n[37]: offset[2] n[36] => _29 @ bb12[15]: fn insertion_sort; - n[38]: addr.load n[37] => _ @ bb14[2]: fn insertion_sort; - n[39]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; - n[40]: offset[3] n[39] => _35 @ bb14[11]: fn insertion_sort; - n[41]: addr.store n[40] => _ @ bb15[2]: fn insertion_sort; + n[34]: offset[2] n[33] => _21 @ bb11[5]: fn insertion_sort; + n[35]: addr.load n[34] => _ @ bb12[2]: fn insertion_sort; + n[36]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; + n[37]: offset[2] n[36] => _30 @ bb15[5]: fn insertion_sort; + n[38]: addr.load n[37] => _ @ bb16[2]: fn insertion_sort; + n[39]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; + n[40]: offset[3] n[39] => _37 @ bb16[11]: fn insertion_sort; + n[41]: addr.store n[40] => _ @ bb17[2]: fn insertion_sort; n[42]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[43]: offset[1] n[42] => _21 @ bb9[16]: fn insertion_sort; - n[44]: addr.load n[43] => _ @ bb11[2]: fn insertion_sort; - n[45]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; - n[46]: offset[1] n[45] => _29 @ bb12[15]: fn insertion_sort; - n[47]: addr.load n[46] => _ @ bb14[2]: fn insertion_sort; - n[48]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; - n[49]: offset[2] n[48] => _35 @ bb14[11]: fn insertion_sort; - n[50]: addr.store n[49] => _ @ bb15[2]: fn insertion_sort; + n[43]: offset[1] n[42] => _21 @ bb11[5]: fn insertion_sort; + n[44]: addr.load n[43] => _ @ bb12[2]: fn insertion_sort; + n[45]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; + n[46]: offset[1] n[45] => _30 @ bb15[5]: fn insertion_sort; + n[47]: addr.load n[46] => _ @ bb16[2]: fn insertion_sort; + n[48]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; + n[49]: offset[2] n[48] => _37 @ bb16[11]: fn insertion_sort; + n[50]: addr.store n[49] => _ @ bb17[2]: fn insertion_sort; n[51]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[52]: offset[0] n[51] => _21 @ bb9[16]: fn insertion_sort; - n[53]: addr.load n[52] => _ @ bb11[2]: fn insertion_sort; - n[54]: copy n[2] => _30 @ bb12[4]: fn insertion_sort; - n[55]: offset[0] n[54] => _29 @ bb12[15]: fn insertion_sort; - n[56]: addr.load n[55] => _ @ bb14[2]: fn insertion_sort; - n[57]: copy n[2] => _36 @ bb14[6]: fn insertion_sort; - n[58]: offset[1] n[57] => _35 @ bb14[11]: fn insertion_sort; - n[59]: addr.store n[58] => _ @ bb15[2]: fn insertion_sort; - n[60]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; - n[61]: offset[0] n[60] => _43 @ bb21[13]: fn insertion_sort; - n[62]: addr.store n[61] => _ @ bb22[2]: fn insertion_sort; + n[52]: offset[0] n[51] => _21 @ bb11[5]: fn insertion_sort; + n[53]: addr.load n[52] => _ @ bb12[2]: fn insertion_sort; + n[54]: copy n[2] => _31 @ bb13[4]: fn insertion_sort; + n[55]: offset[0] n[54] => _30 @ bb15[5]: fn insertion_sort; + n[56]: addr.load n[55] => _ @ bb16[2]: fn insertion_sort; + n[57]: copy n[2] => _38 @ bb16[6]: fn insertion_sort; + n[58]: offset[1] n[57] => _37 @ bb16[11]: fn insertion_sort; + n[59]: addr.store n[58] => _ @ bb17[2]: fn insertion_sort; + n[60]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; + n[61]: offset[0] n[60] => _46 @ bb24[13]: fn insertion_sort; + n[62]: addr.store n[61] => _ @ bb25[2]: fn insertion_sort; n[63]: copy n[2] => _10 @ bb3[4]: fn insertion_sort; n[64]: offset[4] n[63] => _9 @ bb3[9]: fn insertion_sort; n[65]: addr.load n[64] => _ @ bb5[2]: fn insertion_sort; n[66]: copy n[2] => _22 @ bb9[5]: fn insertion_sort; - n[67]: offset[3] n[66] => _21 @ bb9[16]: fn insertion_sort; - n[68]: addr.load n[67] => _ @ bb11[2]: fn insertion_sort; - n[69]: copy n[2] => _44 @ bb21[8]: fn insertion_sort; - n[70]: offset[4] n[69] => _43 @ bb21[13]: fn insertion_sort; - n[71]: addr.store n[70] => _ @ bb22[2]: fn insertion_sort; + n[67]: offset[3] n[66] => _21 @ bb11[5]: fn insertion_sort; + n[68]: addr.load n[67] => _ @ bb12[2]: fn insertion_sort; + n[69]: copy n[2] => _47 @ bb24[8]: fn insertion_sort; + n[70]: offset[4] n[69] => _46 @ bb24[13]: fn insertion_sort; + n[71]: addr.store n[70] => _ @ bb25[2]: fn insertion_sort; } nodes_that_need_write = [71, 70, 69, 62, 61, 60, 59, 58, 57, 50, 49, 48, 41, 40, 39, 29, 28, 27, 23, 22, 21, 11, 10, 9, 2, 1, 0] From 3c81f030cd2f131e3582b0863224621c84afe30d Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Fri, 22 Jul 2022 16:25:22 -0700 Subject: [PATCH 20/50] Allow `NotFound` errors on `target/` when looking for files to delete. --- dynamic_instrumentation/src/main.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 633d7b0419..03cb976f45 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -319,7 +319,15 @@ fn delete_metadata_and_dependencies( // TODO(kkysen) We probably have to delete binaries that have different names from the crates. // Delete all executables in `target/${profile}/deps/` starting with the crate name + `-`. - for profile_dir in cargo_metadata.target_directory.read_dir()? { + let target_read_dir = match cargo_metadata.target_directory.read_dir() { + Ok(read_dir) => Ok(read_dir), + Err(e) => if e.kind() == ErrorKind::NotFound { + return Ok(()); + } else { + Err(e) + } + }?; + for profile_dir in target_read_dir { let profile_dir = profile_dir?; if !profile_dir.file_type()?.is_dir() { continue; From 035670ec7b8eb95592ce9f28aed720956e583b8d Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:27:41 -0700 Subject: [PATCH 21/50] Use `cargo clean --package` to clean the root package instead of trying to do it manually. --- Cargo.lock | 10 ---- dynamic_instrumentation/Cargo.toml | 1 - dynamic_instrumentation/src/main.rs | 90 +++++------------------------ 3 files changed, 16 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26d055fa32..55c4e66be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,7 +282,6 @@ dependencies = [ "env_logger", "fs-err", "indexmap", - "is_executable", "lazy_static", "log", "rustc-private-link", @@ -1155,15 +1154,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "is_executable" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" -dependencies = [ - "winapi", -] - [[package]] name = "itertools" version = "0.10.3" diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index a815c00b3a..b10267e688 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -20,7 +20,6 @@ cargo_metadata = "0.15" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" camino = "1.0" -is_executable = "1.0" [build-dependencies] rustc-private-link = { path = "../rustc-private-link" } diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 03cb976f45..edc4194467 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -7,7 +7,6 @@ use std::{ env, ffi::OsString, hash::Hash, - io::ErrorKind, path::{Path, PathBuf}, process::{self, Command, ExitStatus}, str::FromStr, @@ -15,11 +14,10 @@ use std::{ use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; use camino::Utf8Path; -use cargo_metadata::{Metadata, MetadataCommand, Package, Target}; +use cargo_metadata::{MetadataCommand, Package, Target}; use clap::Parser; use color_eyre::eyre; use color_eyre::eyre::eyre; -use is_executable::IsExecutable; use rustc_driver::RunCompiler; use rustc_session::config::Options; use serde::{Deserialize, Serialize}; @@ -222,14 +220,6 @@ impl CrateTarget { }) } - pub fn from_metadata(metadata: &Metadata) -> eyre::Result> { - Self::from_metadata_package( - metadata - .root_package() - .ok_or_else(|| eyre!("no root package found by `cargo`"))?, - ) - } - pub fn from_rustc_args(at_args: &[String]) -> eyre::Result { let args = rustc_driver::args::arg_expand_all(at_args); let matches = rustc_driver::handle_options(&args) @@ -301,64 +291,6 @@ fn instrument_rustc(mut at_args: Vec, sysroot: &Path, metadata: &Path) - Ok(()) } -/// Delete all files that we want to be regenerated -/// so that we always have fully-up-to-date, non-incremental metadata. -fn delete_metadata_and_dependencies( - info: &InstrumentInfo, - cargo_metadata: &Metadata, -) -> eyre::Result<()> { - if let Err(e) = fs_err::remove_file(&info.metadata) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - // TODO(kkysen) Figure out a way to know which profile is being used - // Until then, just search them all and delete all of them. - - // TODO(kkysen) We probably have to delete binaries that have different names from the crates. - - // Delete all executables in `target/${profile}/deps/` starting with the crate name + `-`. - let target_read_dir = match cargo_metadata.target_directory.read_dir() { - Ok(read_dir) => Ok(read_dir), - Err(e) => if e.kind() == ErrorKind::NotFound { - return Ok(()); - } else { - Err(e) - } - }?; - for profile_dir in target_read_dir { - let profile_dir = profile_dir?; - if !profile_dir.file_type()?.is_dir() { - continue; - } - for artifact in profile_dir.path().join("deps").read_dir()? { - let artifact = artifact?; - if !artifact.file_type()?.is_file() { - continue; - } - let file_name = artifact.file_name(); - let file_name = file_name.to_str(); - for crate_target in &info.crate_targets { - let prefix = format!("{}-", crate_target.crate_name.as_str()); - // [`Path::starts_with`] only checks whole components at once, - // and `OsStr::starts_with` doesn't exist yet. - if file_name - .map(|name| name.starts_with(&prefix)) - .unwrap_or_default() - { - let artifact = artifact.path(); - if artifact.is_executable() { - fs_err::remove_file(&artifact)?; - } - } - } - } - } - - Ok(()) -} - fn main() -> eyre::Result<()> { color_eyre::install()?; env_logger::init(); @@ -389,20 +321,30 @@ fn main() -> eyre::Result<()> { } = Args::parse(); let cargo_metadata = MetadataCommand::new().exec()?; - let crate_targets = CrateTarget::from_metadata(&cargo_metadata)?; + + let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + + let root_package = cargo_metadata + .root_package() + .ok_or_else(|| eyre!("no root package found by `cargo`"))?; + let status = Command::new(&cargo) + .args(&["clean", "--package", root_package.name.as_str()]) + .status()?; + if !status.success() { + exit_with_status(status); + } + + let crate_targets = CrateTarget::from_metadata_package(root_package)?; let info = InstrumentInfo { crate_targets, metadata, }; - delete_metadata_and_dependencies(&info, &cargo_metadata)?; - // We could binary encode this, but it's likely very short, // so just json encode it, so it's also human readable and inspectable. let info = serde_json::to_string(&info)?; - let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); - let status = Command::new(cargo) + let status = Command::new(&cargo) .args(cargo_args) .env(rustc_wrapper_var, &own_exe) .env(instrument_info_var, info) From cd390cbdb0fcb285df0ace794df428059c67ffbe Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:28:09 -0700 Subject: [PATCH 22/50] Use `$CARGO` for `cargo metadata` if possible. --- dynamic_instrumentation/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index edc4194467..31d71ecbf8 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -320,10 +320,10 @@ fn main() -> eyre::Result<()> { cargo_args, } = Args::parse(); - let cargo_metadata = MetadataCommand::new().exec()?; - let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + let cargo_metadata = MetadataCommand::new().cargo_path(&cargo).exec()?; + let root_package = cargo_metadata .root_package() .ok_or_else(|| eyre!("no root package found by `cargo`"))?; From a1fdf172fd7abaaf387c69a949748d68f2c22cba Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:40:48 -0700 Subject: [PATCH 23/50] Switched to using `$CARGO_PRIMARY_PACKAGE` (as suggested by @rinon) instead of passing the crate targets manually, asserting that they're the same. --- dynamic_instrumentation/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 31d71ecbf8..98564e1f29 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -307,7 +307,9 @@ fn main() -> eyre::Result<()> { let crate_target = CrateTarget::from_rustc_args(&at_args)?; let info = env::var(instrument_info_var)?; let info = serde_json::from_str::(&info)?; - let should_instrument = info.crate_targets.contains(&crate_target); + let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); + assert_eq!(is_primary_package, info.crate_targets.contains(&crate_target)); + let should_instrument = is_primary_package; if should_instrument { instrument_rustc(at_args, &sysroot, &info.metadata)?; } else { From d28775ae0f5a1404ee8f24e2d570e3a37d25fc6c Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:41:42 -0700 Subject: [PATCH 24/50] Now removed the crate target passing as `$CARGO_PRIMARY_PACKAGE` works. --- dynamic_instrumentation/src/main.rs | 205 +--------------------------- 1 file changed, 2 insertions(+), 203 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 98564e1f29..0a148c5d5b 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -6,20 +6,17 @@ extern crate rustc_span; use std::{ env, ffi::OsString, - hash::Hash, path::{Path, PathBuf}, process::{self, Command, ExitStatus}, - str::FromStr, }; use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; use camino::Utf8Path; -use cargo_metadata::{MetadataCommand, Package, Target}; +use cargo_metadata::MetadataCommand; use clap::Parser; use color_eyre::eyre; use color_eyre::eyre::eyre; use rustc_driver::RunCompiler; -use rustc_session::config::Options; use serde::{Deserialize, Serialize}; /// Instrument memory accesses for dynamic analysis. @@ -38,201 +35,8 @@ fn exit_with_status(status: ExitStatus) { process::exit(status.code().unwrap_or(1)) } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -enum CrateType { - Bin, - RLib, - DyLib, - CDyLib, - StaticLib, - ProcMacro, -} - -impl FromStr for CrateType { - type Err = eyre::Report; - - fn from_str(s: &str) -> Result { - use CrateType::*; - Ok(match s { - "bin" => Bin, - // `rustc_session::config::CrateType` doesn't have a separate [`Lib`] variant. - "lib" | "rlib" => RLib, - "dylib" => DyLib, - "cdylib" => CDyLib, - "staticlib" => StaticLib, - "proc-macro" => ProcMacro, - _ => return Err(eyre!("unknown crate type: {s}")), - }) - } -} - -impl From for CrateType { - fn from(crate_type: rustc_session::config::CrateType) -> Self { - use rustc_session::config::CrateType::*; - match crate_type { - Executable => Self::Bin, - Dylib => Self::DyLib, - Rlib => Self::RLib, - Staticlib => Self::StaticLib, - Cdylib => Self::CDyLib, - ProcMacro => Self::ProcMacro, - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -enum CrateEdition { - E2015, - E2018, - E2021, -} - -impl From for CrateEdition { - fn from(edition: cargo_metadata::Edition) -> Self { - use cargo_metadata::Edition::*; - match edition { - E2015 => Self::E2015, - E2018 => Self::E2018, - E2021 => Self::E2021, - _ => todo!("when `rustc_span::edition::Edition` gets a new edition, it'll cause a compile error"), - } - } -} - -impl From for CrateEdition { - fn from(edition: rustc_span::edition::Edition) -> Self { - use rustc_span::edition::Edition::*; - match edition { - Edition2015 => Self::E2015, - Edition2018 => Self::E2018, - Edition2021 => Self::E2021, - } - } -} - -/// A `crate` name, canonicalized to an identifier (i.e. `-`s are replaced with `_`). -#[derive(PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -struct CrateName { - name: String, -} - -impl CrateName { - pub fn as_str(&self) -> &str { - self.name.as_str() - } -} - -impl From<&str> for CrateName { - fn from(name: &str) -> Self { - Self { - name: name.replace('-', "_"), - } - } -} - -#[derive(Eq, Debug, Serialize, Deserialize)] -struct CrateTarget { - crate_name: CrateName, - src_path: PathBuf, - crate_types: Vec, - edition: CrateEdition, -} - -impl CrateTarget { - /// A set of stable parts of a [`CrateTarget`] that are meant to be checked for equality. - fn stable_parts(&self) -> impl Eq + Hash + '_ { - // Sometimes the [`CrateType`]s can change to `[]` depending on if tests are being built, - // so exclude that from equality checks. - ( - self.crate_name.as_str(), - self.src_path.as_path(), - self.edition, - ) - } -} - -impl PartialEq for CrateTarget { - fn eq(&self, other: &Self) -> bool { - self.stable_parts() == other.stable_parts() - } -} - -impl Hash for CrateTarget { - fn hash(&self, state: &mut H) { - self.stable_parts().hash(state); - } -} - -impl CrateTarget { - pub fn from_metadata_target(package: &Package, target: &Target) -> eyre::Result { - Ok(Self { - crate_name: package.name.as_str().into(), - src_path: target.src_path.clone().into(), - crate_types: target - .crate_types - .iter() - .map(|s| s.as_str()) - .map(CrateType::from_str) - .collect::, _>>()?, - edition: target.edition.clone().into(), - }) - } - - pub fn from_metadata_package(package: &Package) -> eyre::Result> { - package - .targets - .iter() - .map(|target| Self::from_metadata_target(package, target)) - .collect() - } - - pub fn from_session_options( - session_options: Options, - free_matches: &[String], - ) -> eyre::Result { - let src_path = match free_matches { - [src_path] => { - if src_path == "-" { - // We don't actually ever read from this, so I think this is a fine translation to a real [`Path`]. - "/dev/stdin".into() - } else { - fs_err::canonicalize(src_path)? - } - } - free_matches => { - return Err(eyre!( - "`rustc` args `matches.free` is not a single source path: {free_matches:?}" - )) - } - }; - let Options { - crate_name, - crate_types, - edition, - .. - } = session_options; - let crate_name = crate_name.ok_or_else(|| eyre!("no crate_name specified by `cargo`"))?; - Ok(Self { - crate_name: crate_name.as_str().into(), - src_path, - crate_types: crate_types.into_iter().map(CrateType::from).collect(), - edition: edition.into(), - }) - } - - pub fn from_rustc_args(at_args: &[String]) -> eyre::Result { - let args = rustc_driver::args::arg_expand_all(at_args); - let matches = rustc_driver::handle_options(&args) - .ok_or_else(|| eyre!("failed to parse `rustc` args"))?; - let session_options = rustc_session::config::build_session_options(&matches); - let crate_target = CrateTarget::from_session_options(session_options, &matches.free)?; - Ok(crate_target) - } -} - #[derive(Debug, Serialize, Deserialize)] struct InstrumentInfo { - crate_targets: Vec, metadata: PathBuf, } @@ -304,13 +108,10 @@ fn main() -> eyre::Result<()> { if wrapping_rustc { let sysroot = get_sysroot()?; let at_args = env::args().skip(1).collect::>(); - let crate_target = CrateTarget::from_rustc_args(&at_args)?; let info = env::var(instrument_info_var)?; let info = serde_json::from_str::(&info)?; let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - assert_eq!(is_primary_package, info.crate_targets.contains(&crate_target)); - let should_instrument = is_primary_package; - if should_instrument { + if is_primary_package { instrument_rustc(at_args, &sysroot, &info.metadata)?; } else { let status = passthrough_rustc(&at_args, &sysroot)?; @@ -336,9 +137,7 @@ fn main() -> eyre::Result<()> { exit_with_status(status); } - let crate_targets = CrateTarget::from_metadata_package(root_package)?; let info = InstrumentInfo { - crate_targets, metadata, }; From 8c5568d3e1d2c0a2136306a0a81df4dd11663e89 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:46:18 -0700 Subject: [PATCH 25/50] Pass the metadata path directly (not through json-encoded `InstrumentInfo`, which allows us to drop the `serde` dependencies). --- Cargo.lock | 2 -- dynamic_instrumentation/Cargo.toml | 2 -- dynamic_instrumentation/src/main.rs | 24 +++++------------------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55c4e66be8..9cc4cbcfc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,8 +285,6 @@ dependencies = [ "lazy_static", "log", "rustc-private-link", - "serde", - "serde_json", ] [[package]] diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index b10267e688..34d01f8b1c 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -17,8 +17,6 @@ color-eyre = "0.6" fs-err = "2" clap = { version = "3.2", features = ["derive"] } cargo_metadata = "0.15" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" camino = "1.0" [build-dependencies] diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 0a148c5d5b..f2d6ec3c09 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -17,7 +17,6 @@ use clap::Parser; use color_eyre::eyre; use color_eyre::eyre::eyre; use rustc_driver::RunCompiler; -use serde::{Deserialize, Serialize}; /// Instrument memory accesses for dynamic analysis. #[derive(Debug, Parser)] @@ -35,11 +34,6 @@ fn exit_with_status(status: ExitStatus) { process::exit(status.code().unwrap_or(1)) } -#[derive(Debug, Serialize, Deserialize)] -struct InstrumentInfo { - metadata: PathBuf, -} - fn get_sysroot_fast() -> Option { let sysroot = [ env::var_os("RUSTUP_HOME")?, @@ -100,7 +94,7 @@ fn main() -> eyre::Result<()> { env_logger::init(); let rustc_wrapper_var = "RUSTC_WRAPPER"; - let instrument_info_var = "C2RUST_INSTRUMENT_INFO"; + let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; let own_exe = env::current_exe()?; @@ -108,11 +102,11 @@ fn main() -> eyre::Result<()> { if wrapping_rustc { let sysroot = get_sysroot()?; let at_args = env::args().skip(1).collect::>(); - let info = env::var(instrument_info_var)?; - let info = serde_json::from_str::(&info)?; let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); if is_primary_package { - instrument_rustc(at_args, &sysroot, &info.metadata)?; + let metadata = + env::var_os(metadata_var).ok_or_else(|| eyre!("we should've set this"))?; + instrument_rustc(at_args, &sysroot, Path::new(&metadata))?; } else { let status = passthrough_rustc(&at_args, &sysroot)?; exit_with_status(status); @@ -137,18 +131,10 @@ fn main() -> eyre::Result<()> { exit_with_status(status); } - let info = InstrumentInfo { - metadata, - }; - - // We could binary encode this, but it's likely very short, - // so just json encode it, so it's also human readable and inspectable. - let info = serde_json::to_string(&info)?; - let status = Command::new(&cargo) .args(cargo_args) .env(rustc_wrapper_var, &own_exe) - .env(instrument_info_var, info) + .env(metadata_var, metadata) .status()?; exit_with_status(status); } From 63beb5e2ff72108eebcbabf9fa0d9eda4c1ede5e Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:57:48 -0700 Subject: [PATCH 26/50] Remove `env-logger` dependency. Not sure why I added it. --- Cargo.lock | 1 - dynamic_instrumentation/Cargo.toml | 1 - dynamic_instrumentation/src/main.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cc4cbcfc7..678b3ddbab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,7 +279,6 @@ dependencies = [ "cargo_metadata", "clap 3.2.8", "color-eyre", - "env_logger", "fs-err", "indexmap", "lazy_static", diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index 34d01f8b1c..1027a67951 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -12,7 +12,6 @@ cargo-util = "0.1" indexmap = "1.8" lazy_static = "1.4" log = "0.4" -env_logger = "0.9" color-eyre = "0.6" fs-err = "2" clap = { version = "3.2", features = ["derive"] } diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index f2d6ec3c09..5c7d596cf6 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -91,7 +91,6 @@ fn instrument_rustc(mut at_args: Vec, sysroot: &Path, metadata: &Path) - fn main() -> eyre::Result<()> { color_eyre::install()?; - env_logger::init(); let rustc_wrapper_var = "RUSTC_WRAPPER"; let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; From 045c62d7ada40b73fa67aa6521e8d62dc1185073 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 14:59:31 -0700 Subject: [PATCH 27/50] Replaced `eyre` with `anyhow` by a literal find and replace. --- Cargo.lock | 1 - dynamic_instrumentation/Cargo.toml | 1 - dynamic_instrumentation/src/main.rs | 27 ++++++++++++++------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 678b3ddbab..4dec9764a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,7 +278,6 @@ dependencies = [ "cargo-util", "cargo_metadata", "clap 3.2.8", - "color-eyre", "fs-err", "indexmap", "lazy_static", diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index 1027a67951..d5418a6ae6 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -12,7 +12,6 @@ cargo-util = "0.1" indexmap = "1.8" lazy_static = "1.4" log = "0.4" -color-eyre = "0.6" fs-err = "2" clap = { version = "3.2", features = ["derive"] } cargo_metadata = "0.15" diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 5c7d596cf6..48e0ea42da 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -10,12 +10,11 @@ use std::{ process::{self, Command, ExitStatus}, }; +use anyhow::anyhow; use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; -use color_eyre::eyre; -use color_eyre::eyre::eyre; use rustc_driver::RunCompiler; /// Instrument memory accesses for dynamic analysis. @@ -45,17 +44,17 @@ fn get_sysroot_fast() -> Option { Some(sysroot) } -fn get_sysroot_slow() -> eyre::Result { +fn get_sysroot_slow() -> anyhow::Result { todo!("use `rustc --print sysroot` to support non-`rustup` cases, which @fw-immunant uses") } -fn get_sysroot() -> eyre::Result { +fn get_sysroot() -> anyhow::Result { get_sysroot_fast() .ok_or(()) .or_else(|()| get_sysroot_slow()) } -fn passthrough_rustc(at_args: &[String], sysroot: &Path) -> eyre::Result { +fn passthrough_rustc(at_args: &[String], sysroot: &Path) -> anyhow::Result { // We can skip a `rustup` `rustc` -> real `rustc` resolution by just invoking the real `rustc` ourselves. // TODO(kkysen) this might not work without `rustup` let rustc = sysroot.join("bin/rustc"); @@ -63,7 +62,11 @@ fn passthrough_rustc(at_args: &[String], sysroot: &Path) -> eyre::Result, sysroot: &Path, metadata: &Path) -> eyre::Result<()> { +fn instrument_rustc( + mut at_args: Vec, + sysroot: &Path, + metadata: &Path, +) -> anyhow::Result<()> { // Normally, `rustc` looks up the sysroot by the location of its own binary. // This works because the `rustc` on `$PATH` is actually `rustup`, // and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. @@ -84,14 +87,12 @@ fn instrument_rustc(mut at_args: Vec, sysroot: &Path, metadata: &Path) - at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); RunCompiler::new(&at_args, &mut MirTransformCallbacks) .run() - .map_err(|_| eyre!("`rustc` failed"))?; - INSTRUMENTER.finalize(metadata).map_err(|e| eyre!(e))?; + .map_err(|_| anyhow!("`rustc` failed"))?; + INSTRUMENTER.finalize(metadata).map_err(|e| anyhow!(e))?; Ok(()) } -fn main() -> eyre::Result<()> { - color_eyre::install()?; - +fn main() -> anyhow::Result<()> { let rustc_wrapper_var = "RUSTC_WRAPPER"; let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; @@ -104,7 +105,7 @@ fn main() -> eyre::Result<()> { let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); if is_primary_package { let metadata = - env::var_os(metadata_var).ok_or_else(|| eyre!("we should've set this"))?; + env::var_os(metadata_var).ok_or_else(|| anyhow!("we should've set this"))?; instrument_rustc(at_args, &sysroot, Path::new(&metadata))?; } else { let status = passthrough_rustc(&at_args, &sysroot)?; @@ -122,7 +123,7 @@ fn main() -> eyre::Result<()> { let root_package = cargo_metadata .root_package() - .ok_or_else(|| eyre!("no root package found by `cargo`"))?; + .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; let status = Command::new(&cargo) .args(&["clean", "--package", root_package.name.as_str()]) .status()?; From d8c0b4922fc5f7a38e3a81381eb83bf4fd8afab1 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 15:00:27 -0700 Subject: [PATCH 28/50] Removed a redundant `anyhow` to `eyre` conversion now that we're back to `anyhow`. --- dynamic_instrumentation/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 48e0ea42da..a2083a77e5 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -88,7 +88,7 @@ fn instrument_rustc( RunCompiler::new(&at_args, &mut MirTransformCallbacks) .run() .map_err(|_| anyhow!("`rustc` failed"))?; - INSTRUMENTER.finalize(metadata).map_err(|e| anyhow!(e))?; + INSTRUMENTER.finalize(metadata)?; Ok(()) } From c035e75e88465371541e2398436a050abee714c5 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:23:35 -0700 Subject: [PATCH 29/50] In the non-instrumenting case, use `RunCompiler` instead of invoking `rustc`, as it guarantees the same version is used. --- dynamic_instrumentation/src/main.rs | 87 ++++++++++++++--------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index a2083a77e5..8d90f361d5 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -11,7 +11,7 @@ use std::{ }; use anyhow::anyhow; -use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; +use c2rust_dynamic_instrumentation::{MirTransformCallbacks, NullCallbacks, INSTRUMENTER}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; @@ -48,50 +48,30 @@ fn get_sysroot_slow() -> anyhow::Result { todo!("use `rustc --print sysroot` to support non-`rustup` cases, which @fw-immunant uses") } +/// Resolve the current `rustc` sysroot. +/// +/// Normally, `rustc` looks up the sysroot by the location of its own binary. +/// This works because the `rustc` on `$PATH` is actually `rustup`, +/// and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. +/// As we invoke `rustc_driver` directly here, we are `rustc`, +/// and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. +/// +/// Note that the sysroot contains the toolchain and host target name, +/// but this has no effect on cross-compiling. +/// Every toolchain's `rustc` is able to itself cross-compile. +/// I'm not sure why the host target needs to be in the sysroot directory name, but it is. +/// +/// Also note that this sysroot lookup should be done at runtime, +/// not at compile-time in the `build.rs`, +/// as the toolchain locations could be different +/// from where this binary was compiled and where it is running +/// (it could be on a different machine with a different `$RUSTUP_HOME`). fn get_sysroot() -> anyhow::Result { get_sysroot_fast() .ok_or(()) .or_else(|()| get_sysroot_slow()) } -fn passthrough_rustc(at_args: &[String], sysroot: &Path) -> anyhow::Result { - // We can skip a `rustup` `rustc` -> real `rustc` resolution by just invoking the real `rustc` ourselves. - // TODO(kkysen) this might not work without `rustup` - let rustc = sysroot.join("bin/rustc"); - let status = Command::new(rustc).args(at_args.iter().skip(1)).status()?; - Ok(status) -} - -fn instrument_rustc( - mut at_args: Vec, - sysroot: &Path, - metadata: &Path, -) -> anyhow::Result<()> { - // Normally, `rustc` looks up the sysroot by the location of its own binary. - // This works because the `rustc` on `$PATH` is actually `rustup`, - // and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. - // As we invoke `rustc_driver` directly here, we are `rustc`, - // and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. - // - // Note that the sysroot contains the toolchain and host target name, - // but this has no effect on cross-compiling. - // Every toolchain's `rustc` is able to itself cross-compile. - // I'm not sure why the host target needs to be in the sysroot directory name, but it is. - // - // Also note that this sysroot lookup should be done at runtime, - // not at compile-time in the `build.rs`, - // as the toolchain locations could be different - // from where this binary was compiled and where it is running - // (it could be on a different machine with a different `$RUSTUP_HOME`). - let sysroot: &Utf8Path = sysroot.try_into()?; - at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); - RunCompiler::new(&at_args, &mut MirTransformCallbacks) - .run() - .map_err(|_| anyhow!("`rustc` failed"))?; - INSTRUMENTER.finalize(metadata)?; - Ok(()) -} - fn main() -> anyhow::Result<()> { let rustc_wrapper_var = "RUSTC_WRAPPER"; let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; @@ -100,16 +80,30 @@ fn main() -> anyhow::Result<()> { let wrapping_rustc = env::var_os(rustc_wrapper_var).as_deref() == Some(own_exe.as_os_str()); if wrapping_rustc { - let sysroot = get_sysroot()?; - let at_args = env::args().skip(1).collect::>(); let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - if is_primary_package { + let should_instrument = is_primary_package; + let mut at_args = env::args().skip(1).collect::>(); + let sysroot = get_sysroot()?; + let sysroot: &Utf8Path = sysroot.as_path().try_into()?; + at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); + let result = if should_instrument { + RunCompiler::new(&at_args, &mut MirTransformCallbacks).run() + } else { + // Always use the dynamically linked `librustc_driver-{hash}.so`, + // as it is guaranteed to be the same version as the instrumented version. + // Furthermore, we can't accidentally load the wrong `librustc_driver-{hash}.so`, + // as it contains its hash. + // This also avoids an extra `rustc` (and potentially `rustup` `rustc`) invocation. + RunCompiler::new(&at_args, &mut NullCallbacks).run() + }; + // `ErrorReported` means the error has already been reported to the user, + // so we just have to fail/exit with a failing exit code. + // There is no `impl Error for ErrorReported`. + result.map_err(|_| anyhow!("`rustc` failed"))?; + if should_instrument { let metadata = env::var_os(metadata_var).ok_or_else(|| anyhow!("we should've set this"))?; - instrument_rustc(at_args, &sysroot, Path::new(&metadata))?; - } else { - let status = passthrough_rustc(&at_args, &sysroot)?; - exit_with_status(status); + INSTRUMENTER.finalize(Path::new(&metadata))?; } } else { let Args { @@ -124,6 +118,7 @@ fn main() -> anyhow::Result<()> { let root_package = cargo_metadata .root_package() .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; + let status = Command::new(&cargo) .args(&["clean", "--package", root_package.name.as_str()]) .status()?; From 8e9e94e7e1742983a38343925a1f847aff1a7ba9 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:25:17 -0700 Subject: [PATCH 30/50] Use `TimePassesCallbacks::default()` instead of `NullCallbacks` as this is what `rustc` uses itself. --- dynamic_instrumentation/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 8d90f361d5..763e3e5814 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -11,11 +11,11 @@ use std::{ }; use anyhow::anyhow; -use c2rust_dynamic_instrumentation::{MirTransformCallbacks, NullCallbacks, INSTRUMENTER}; +use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; -use rustc_driver::RunCompiler; +use rustc_driver::{RunCompiler, TimePassesCallbacks}; /// Instrument memory accesses for dynamic analysis. #[derive(Debug, Parser)] @@ -94,7 +94,7 @@ fn main() -> anyhow::Result<()> { // Furthermore, we can't accidentally load the wrong `librustc_driver-{hash}.so`, // as it contains its hash. // This also avoids an extra `rustc` (and potentially `rustup` `rustc`) invocation. - RunCompiler::new(&at_args, &mut NullCallbacks).run() + RunCompiler::new(&at_args, &mut TimePassesCallbacks::default()).run() }; // `ErrorReported` means the error has already been reported to the user, // so we just have to fail/exit with a failing exit code. From 0ab0a3084626c238f20227e459ededb1d6c3fa78 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:42:20 -0700 Subject: [PATCH 31/50] Removed the old `cargo` dependency version and all its dependencies, which include the `c2rust-instrument` binary in the `c2rust` crate and `--feature dynamic-instrumentation`. --- Cargo.lock | 834 ---------------------------- c2rust/Cargo.toml | 6 - c2rust/src/bin/c2rust-instrument.rs | 21 - c2rust/src/instrument.yaml | 20 - c2rust/src/main.rs | 2 +- dynamic_instrumentation/Cargo.toml | 2 - dynamic_instrumentation/src/lib.rs | 115 ---- 7 files changed, 1 insertion(+), 999 deletions(-) delete mode 100644 c2rust/src/bin/c2rust-instrument.rs delete mode 100644 c2rust/src/instrument.yaml diff --git a/Cargo.lock b/Cargo.lock index 4dec9764a8..4bf7a1a954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,12 +47,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" @@ -121,15 +115,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - [[package]] name = "block-buffer" version = "0.7.3" @@ -151,17 +136,6 @@ dependencies = [ "byte-tools", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", -] - [[package]] name = "byte-tools" version = "0.3.1" @@ -174,24 +148,11 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "bytesize" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" - [[package]] name = "c2rust" version = "0.16.0" dependencies = [ "anyhow", - "c2rust-dynamic-instrumentation", "c2rust-transpile", "clap 2.34.0", "env_logger", @@ -274,8 +235,6 @@ dependencies = [ "bincode", "c2rust-analysis-rt", "camino", - "cargo", - "cargo-util", "cargo_metadata", "clap 3.2.8", "fs-err", @@ -345,64 +304,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo" -version = "0.62.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79bc435c2de37f164b5c36420d9e1dd65cd5acbd41b2df10fdc02dbf75ed9efc" -dependencies = [ - "anyhow", - "atty", - "bytesize", - "cargo-platform", - "cargo-util", - "clap 3.2.8", - "crates-io", - "crossbeam-utils", - "curl", - "curl-sys", - "env_logger", - "filetime", - "flate2", - "fwdansi", - "git2", - "git2-curl", - "glob", - "hex 0.4.3", - "home", - "humantime", - "ignore", - "im-rc", - "itertools", - "jobserver", - "lazy_static", - "lazycell", - "libc", - "libgit2-sys", - "log", - "memchr", - "opener", - "os_info", - "percent-encoding", - "rustc-workspace-hack", - "rustfix", - "semver", - "serde", - "serde_ignored", - "serde_json", - "shell-escape", - "strip-ansi-escapes", - "tar", - "tempfile", - "termcolor", - "toml_edit", - "unicode-width", - "unicode-xid", - "url", - "walkdir", - "winapi", -] - [[package]] name = "cargo-platform" version = "0.1.2" @@ -412,28 +313,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51c783163bdf4549820b80968d386c94ed45ed23819c93f59cca7ebd97fe0eb" -dependencies = [ - "anyhow", - "core-foundation", - "crypto-hash", - "filetime", - "hex 0.4.3", - "jobserver", - "libc", - "log", - "miow", - "same-file", - "shell-escape", - "tempfile", - "walkdir", - "winapi", -] - [[package]] name = "cargo_metadata" version = "0.15.0" @@ -452,9 +331,6 @@ name = "cc" version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" -dependencies = [ - "jobserver", -] [[package]] name = "cexpr" @@ -594,34 +470,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "combine" -version = "4.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "commoncrypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" -dependencies = [ - "commoncrypto-sys", -] - -[[package]] -name = "commoncrypto-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -dependencies = [ - "libc", -] - [[package]] name = "console" version = "0.15.0" @@ -635,98 +483,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "crates-io" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4a87459133b2e708195eaab34be55039bc30e0d120658bd40794bb00b6328d" -dependencies = [ - "anyhow", - "curl", - "percent-encoding", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "crypto-hash" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a77162240fd97248d19a564a565eb563a3f592b386e4136fb300909e67dddca" -dependencies = [ - "commoncrypto", - "hex 0.3.2", - "openssl", - "winapi", -] - -[[package]] -name = "curl" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.55+curl-7.83.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - [[package]] name = "digest" version = "0.8.1" @@ -817,15 +573,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - [[package]] name = "fern" version = "0.6.1" @@ -836,76 +583,12 @@ dependencies = [ "log", ] -[[package]] -name = "filetime" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "libz-sys", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - [[package]] name = "fs-err" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd79fa345a495d3ae89fb7165fec01c0e72f41821d642dda363a1e97975652e" -[[package]] -name = "fwdansi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208" -dependencies = [ - "memchr", - "termcolor", -] - [[package]] name = "generic-array" version = "0.12.4" @@ -944,52 +627,12 @@ dependencies = [ "time", ] -[[package]] -name = "git2" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c" -dependencies = [ - "bitflags", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "git2-curl" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13" -dependencies = [ - "curl", - "git2", - "log", - "url", -] - [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - [[package]] name = "half" version = "1.8.2" @@ -1031,76 +674,12 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "home" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" -dependencies = [ - "winapi", -] - [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "im-rc" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" -dependencies = [ - "bitmaps", - "rand_core", - "rand_xoshiro", - "sized-chunks", - "typenum", - "version_check", -] - [[package]] name = "indenter" version = "0.3.3" @@ -1141,15 +720,6 @@ dependencies = [ "similar", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "itertools" version = "0.10.3" @@ -1165,24 +735,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "kstring" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526" -dependencies = [ - "serde", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1201,56 +753,6 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" -[[package]] -name = "libgit2-sys" -version = "0.13.4+1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - -[[package]] -name = "libnghttp2-sys" -version = "0.1.7+1.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1292,12 +794,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" version = "2.5.0" @@ -1319,15 +815,6 @@ dependencies = [ "adler", ] -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - [[package]] name = "no-std-compat" version = "0.4.1" @@ -1374,72 +861,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -[[package]] -name = "opener" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" -dependencies = [ - "bstr", - "winapi", -] - -[[package]] -name = "openssl" -version = "0.10.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_info" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" -dependencies = [ - "log", - "serde", - "winapi", -] - [[package]] name = "os_str_bytes" version = "6.1.0" @@ -1464,12 +885,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - [[package]] name = "pest" version = "2.1.3" @@ -1519,12 +934,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - [[package]] name = "prettyplease" version = "0.1.11" @@ -1586,30 +995,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" - -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" version = "1.5.6" @@ -1621,27 +1006,12 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-syntax" version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "rustc-demangle" version = "0.1.21" @@ -1661,24 +1031,6 @@ dependencies = [ "print_bytes", ] -[[package]] -name = "rustc-workspace-hack" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" - -[[package]] -name = "rustfix" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" -dependencies = [ - "anyhow", - "log", - "serde", - "serde_json", -] - [[package]] name = "rustversion" version = "1.0.6" @@ -1691,25 +1043,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys", -] - [[package]] name = "semver" version = "1.0.10" @@ -1768,15 +1101,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_ignored" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1940036ca2411651a40012009d062087dfe62817b2191a03750fb569e11fa633" -dependencies = [ - "serde", -] - [[package]] name = "serde_json" version = "1.0.81" @@ -1821,12 +1145,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-escape" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" - [[package]] name = "shlex" version = "1.1.0" @@ -1839,41 +1157,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - [[package]] name = "smallvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strip-ansi-escapes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" -dependencies = [ - "vte", -] - [[package]] name = "strsim" version = "0.8.0" @@ -1928,30 +1217,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "termcolor" version = "1.1.3" @@ -2033,34 +1298,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "toml_edit" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b" -dependencies = [ - "combine", - "indexmap", - "itertools", - "kstring", - "serde", -] - [[package]] name = "tracing" version = "0.1.35" @@ -2115,27 +1352,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - [[package]] name = "unicode-ident" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.1.9" @@ -2148,36 +1370,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" - [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "vec_map" version = "0.8.2" @@ -2190,38 +1388,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "vte" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" -dependencies = [ - "arrayvec", - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/c2rust/Cargo.toml b/c2rust/Cargo.toml index def1cd26e2..891f991d74 100644 --- a/c2rust/Cargo.toml +++ b/c2rust/Cargo.toml @@ -25,16 +25,10 @@ git-testament = "0.2.1" regex = "1.3" shlex = "1.1" c2rust-transpile = { version = "0.16.0", path = "../c2rust-transpile" } -c2rust-dynamic-instrumentation = { version = "0.1.0", path = "../dynamic_instrumentation", optional = true } [build-dependencies] rustc-private-link = { path = "../rustc-private-link" } -[[bin]] -name = "c2rust-instrument" -required-features = ["dynamic-instrumentation"] - [features] # Force static linking of LLVM llvm-static = ["c2rust-transpile/llvm-static"] -dynamic-instrumentation = ["dep:c2rust-dynamic-instrumentation"] diff --git a/c2rust/src/bin/c2rust-instrument.rs b/c2rust/src/bin/c2rust-instrument.rs deleted file mode 100644 index c88dfcbc51..0000000000 --- a/c2rust/src/bin/c2rust-instrument.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::fs; -use std::path::Path; - -use c2rust_dynamic_instrumentation::instrument; -use clap::{load_yaml, App}; - -fn main() -> anyhow::Result<()> { - env_logger::init(); - let yaml = load_yaml!("../instrument.yaml"); - let matches = App::from_yaml(yaml).get_matches(); - - let extra_args: Vec<&str> = match matches.values_of("extra-cargo-args") { - Some(args) => args.collect(), - None => Vec::new(), - }; - let extra_args: Vec = extra_args.into_iter().map(|x| x.to_owned()).collect(); - - let metadata_file_path = Path::new(matches.value_of_os("METADATA_FILE").unwrap()); - let runtime_path = fs::canonicalize(matches.value_of_os("RUNTIME_PATH").unwrap()).unwrap(); - instrument(metadata_file_path, &runtime_path, &extra_args) -} diff --git a/c2rust/src/instrument.yaml b/c2rust/src/instrument.yaml deleted file mode 100644 index 68d739f3a7..0000000000 --- a/c2rust/src/instrument.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: instrument -version: 0.16.0 -author: | - - The C2Rust Project Developers -about: Instrument memory accesses for dynamic analysis -settings: - - TrailingVarArg -args: - - METADATA_FILE: - help: Path to the metadata output file storing instrumentation locations - required: true - index: 1 - - RUNTIME_PATH: - help: Path to the c2rust-analysis-runtime crate - required: true - index: 2 - - extra-cargo-args: - help: Extra arguments to pass to cargo after `build` - takes_value: true - multiple: true \ No newline at end of file diff --git a/c2rust/src/main.rs b/c2rust/src/main.rs index 89bd421d9b..a58220c931 100644 --- a/c2rust/src/main.rs +++ b/c2rust/src/main.rs @@ -7,7 +7,7 @@ use std::process::{exit, Command}; git_testament!(TESTAMENT); fn main() { - let subcommand_yamls = [load_yaml!("transpile.yaml"), load_yaml!("instrument.yaml")]; + let subcommand_yamls = [load_yaml!("transpile.yaml")]; let matches = App::new("C2Rust") .version(&*render_testament!(TESTAMENT)) .author(crate_authors!(", ")) diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index d5418a6ae6..ce9f6a522e 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -7,8 +7,6 @@ edition = "2021" anyhow = "1.0" bincode = "1.0.1" c2rust-analysis-rt = { path = "../analysis/runtime"} -cargo = "0.62" -cargo-util = "0.1" indexmap = "1.8" lazy_static = "1.4" log = "0.4" diff --git a/dynamic_instrumentation/src/lib.rs b/dynamic_instrumentation/src/lib.rs index 2685756469..4860297839 100644 --- a/dynamic_instrumentation/src/lib.rs +++ b/dynamic_instrumentation/src/lib.rs @@ -15,15 +15,6 @@ extern crate rustc_target; mod instrument_memory; use instrument_memory::InstrumentMemoryOps; -use cargo::core::compiler::{CompileMode, Context, Executor, Unit}; -use cargo::core::{PackageId, Target, Verbosity, Workspace}; -use cargo::ops; -use cargo::ops::CompileOptions; -use cargo::util::important_paths::find_root_manifest_for_wd; -use cargo::util::CargoResult; -use cargo::Config; -use cargo_util::ProcessBuilder; - use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; use rustc_ast::node_id::NodeId; use rustc_ast::ptr::P; @@ -39,22 +30,12 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; -use anyhow::anyhow; use lazy_static::lazy_static; -use std::env; -use std::ffi::OsString; -use std::path::Path; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; lazy_static! { pub static ref INSTRUMENTER: InstrumentMemoryOps = InstrumentMemoryOps::new(); } -pub struct NullCallbacks; - -impl rustc_driver::Callbacks for NullCallbacks {} - pub struct MirTransformCallbacks; impl rustc_driver::Callbacks for MirTransformCallbacks { @@ -113,99 +94,3 @@ fn override_queries( tcx.alloc_steal_mir(mir) }; } - -pub fn instrument( - metadata_file_path: &Path, - rt_path: &Path, - _args: &[String], -) -> anyhow::Result<()> { - let config = Config::default().unwrap(); - config.shell().set_verbosity(Verbosity::Quiet); - let mode = CompileMode::Build; - let compile_opts = CompileOptions::new(&config, mode).unwrap(); - - let manifest_path = find_root_manifest_for_wd(config.cwd()).unwrap(); - let ws = Workspace::new(&manifest_path, &config).unwrap(); - - let rt_manifest_path = find_root_manifest_for_wd(rt_path).unwrap(); - let mut rt_ws = Workspace::new(&rt_manifest_path, &config).unwrap(); - rt_ws.set_target_dir(ws.target_dir()); - - let exec = Arc::new(InstrumentationExecutor { - target_pkg: ws.current().unwrap().package_id(), - rt_crate_path: Mutex::new(String::new()), - building_rt: AtomicBool::new(true), - }); - let exec_dyn: Arc = exec.clone(); - - let cwd = env::current_dir().unwrap(); - - env::set_current_dir(rt_ws.root()).unwrap(); - ops::compile_with_exec(&rt_ws, &compile_opts, &exec_dyn)?; - - exec.building_rt.store(false, Ordering::Relaxed); - env::set_current_dir(cwd).unwrap(); - ops::compile_with_exec(&ws, &compile_opts, &exec_dyn)?; - - INSTRUMENTER.finalize(metadata_file_path) -} -struct InstrumentationExecutor { - target_pkg: PackageId, - rt_crate_path: Mutex, - building_rt: AtomicBool, -} - -impl Executor for InstrumentationExecutor { - fn init(&self, cx: &Context<'_, '_>, unit: &Unit) { - if self.building_rt.load(Ordering::Relaxed) && cx.is_primary_package(unit) { - *self.rt_crate_path.lock().unwrap() = cx.outputs(unit).unwrap()[0] - .path - .to_str() - .unwrap() - .to_owned(); - } - } - - fn exec( - &self, - cmd: &ProcessBuilder, - id: PackageId, - target: &Target, - _mode: CompileMode, - _on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>, - _on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>, - ) -> CargoResult<()> { - let mut args: Vec = cmd - .get_args() - .iter() - .map(|a| a.to_str().unwrap().to_string()) - .collect(); - args.insert(0, cmd.get_program().to_str().unwrap().to_string()); - // We need to point the rust compiler libraries to the corresponding sysroot - args.push(format!("--sysroot={}", env!("RUST_SYSROOT"))); - for (var, val) in cmd.get_envs() { - env::set_var(var, val.as_ref().unwrap_or(&OsString::new())); - } - if id == self.target_pkg && !target.for_host() { - args.push("--extern".to_string()); - args.push(format!( - "c2rust_analysis_rt={}", - self.rt_crate_path.lock().unwrap() - )); - let mut callbacks = MirTransformCallbacks; - // TODO: Capture stdout and pass it back to cargo - rustc_driver::RunCompiler::new(&args, &mut callbacks) - .run() - .map_err(|_| anyhow!("Compilation failed")) - } else { - let mut callbacks = NullCallbacks; - rustc_driver::RunCompiler::new(&args, &mut callbacks) - .run() - .map_err(|_| anyhow!("Compilation failed")) - } - } - - fn force_rebuild(&self, _unit: &Unit) -> bool { - self.building_rt.load(Ordering::Relaxed) - } -} From 676dee2df9e3e2dc1151a1f7c333b69f4d9a191f Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:46:38 -0700 Subject: [PATCH 32/50] Deleted `c2rust-dynamic-instrumentation`'s `lib.rs` and moved it all to `bin.rs`, b/c it should only have a CLI interface. --- dynamic_instrumentation/src/lib.rs | 96 ----------------------------- dynamic_instrumentation/src/main.rs | 96 ++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 99 deletions(-) delete mode 100644 dynamic_instrumentation/src/lib.rs diff --git a/dynamic_instrumentation/src/lib.rs b/dynamic_instrumentation/src/lib.rs deleted file mode 100644 index 4860297839..0000000000 --- a/dynamic_instrumentation/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -#![feature(rustc_private)] -extern crate rustc_ast; -extern crate rustc_const_eval; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_index; -extern crate rustc_interface; -extern crate rustc_middle; -extern crate rustc_mir_build; -extern crate rustc_mir_transform; -extern crate rustc_session; -extern crate rustc_span; -extern crate rustc_target; - -mod instrument_memory; -use instrument_memory::InstrumentMemoryOps; - -use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; -use rustc_ast::node_id::NodeId; -use rustc_ast::ptr::P; -use rustc_const_eval::transform::validate; -use rustc_driver::Compilation; -use rustc_interface::interface::Compiler; -use rustc_interface::Queries; -use rustc_middle::mir::MirPass; -use rustc_middle::ty::query::{ExternProviders, Providers}; -use rustc_middle::ty::WithOptConstParam; -use rustc_session::Session; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::Ident; -use rustc_span::DUMMY_SP; - -use lazy_static::lazy_static; - -lazy_static! { - pub static ref INSTRUMENTER: InstrumentMemoryOps = InstrumentMemoryOps::new(); -} - -pub struct MirTransformCallbacks; - -impl rustc_driver::Callbacks for MirTransformCallbacks { - fn config(&mut self, config: &mut rustc_interface::Config) { - config.override_queries = Some(override_queries); - } - - fn after_parsing<'tcx>( - &mut self, - _compiler: &Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - let parse = queries.parse().unwrap(); - let mut parse = parse.peek_mut(); - parse.items.push(P(Item { - attrs: Vec::new(), - id: NodeId::from_u32(0), - span: DUMMY_SP, - vis: Visibility { - kind: VisibilityKind::Inherited, - span: DUMMY_SP, - tokens: None, - }, - ident: Ident::from_str("c2rust_analysis_rt"), - kind: ItemKind::ExternCrate(None), - tokens: None, - })); - Compilation::Continue - } -} - -fn override_queries( - _sess: &Session, - providers: &mut Providers, - _extern_providers: &mut ExternProviders, -) { - providers.mir_built = |tcx, def: WithOptConstParam| { - let mut providers = Providers::default(); - rustc_mir_build::provide(&mut providers); - - let steal_mir = (providers.mir_built)(tcx, def); - let mut mir = steal_mir.steal(); - - let body_did = def.did.to_def_id(); - let fn_ty = tcx.type_of(body_did); - if fn_ty.is_fn() && !tcx.is_const_fn(body_did) && !tcx.is_static(body_did) { - INSTRUMENTER.instrument_fn(tcx, &mut mir, body_did); - - validate::Validator { - when: "After dynamic instrumentation".to_string(), - mir_phase: mir.phase, - } - .run_pass(tcx, &mut mir); - } - - tcx.alloc_steal_mir(mir) - }; -} diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 763e3e5814..6f5fe7e33f 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -2,6 +2,18 @@ extern crate rustc_driver; extern crate rustc_session; extern crate rustc_span; +extern crate rustc_ast; +extern crate rustc_const_eval; +extern crate rustc_data_structures; +extern crate rustc_index; +extern crate rustc_interface; +extern crate rustc_middle; +extern crate rustc_mir_build; +extern crate rustc_mir_transform; +extern crate rustc_target; + +mod instrument_memory; +use instrument_memory::InstrumentMemoryOps; use std::{ env, @@ -10,12 +22,27 @@ use std::{ process::{self, Command, ExitStatus}, }; +use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; +use rustc_ast::node_id::NodeId; +use rustc_ast::ptr::P; +use rustc_const_eval::transform::validate; +use rustc_driver::Compilation; +use rustc_driver::{RunCompiler, TimePassesCallbacks}; +use rustc_interface::interface::Compiler; +use rustc_interface::Queries; +use rustc_middle::mir::MirPass; +use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::ty::WithOptConstParam; +use rustc_session::Session; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; + use anyhow::anyhow; -use c2rust_dynamic_instrumentation::{MirTransformCallbacks, INSTRUMENTER}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; -use rustc_driver::{RunCompiler, TimePassesCallbacks}; +use lazy_static::lazy_static; /// Instrument memory accesses for dynamic analysis. #[derive(Debug, Parser)] @@ -49,7 +76,7 @@ fn get_sysroot_slow() -> anyhow::Result { } /// Resolve the current `rustc` sysroot. -/// +/// /// Normally, `rustc` looks up the sysroot by the location of its own binary. /// This works because the `rustc` on `$PATH` is actually `rustup`, /// and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. @@ -135,3 +162,66 @@ fn main() -> anyhow::Result<()> { } Ok(()) } + +lazy_static! { + static ref INSTRUMENTER: InstrumentMemoryOps = InstrumentMemoryOps::new(); +} + +struct MirTransformCallbacks; + +impl rustc_driver::Callbacks for MirTransformCallbacks { + fn config(&mut self, config: &mut rustc_interface::Config) { + config.override_queries = Some(override_queries); + } + + fn after_parsing<'tcx>( + &mut self, + _compiler: &Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { + let parse = queries.parse().unwrap(); + let mut parse = parse.peek_mut(); + parse.items.push(P(Item { + attrs: Vec::new(), + id: NodeId::from_u32(0), + span: DUMMY_SP, + vis: Visibility { + kind: VisibilityKind::Inherited, + span: DUMMY_SP, + tokens: None, + }, + ident: Ident::from_str("c2rust_analysis_rt"), + kind: ItemKind::ExternCrate(None), + tokens: None, + })); + Compilation::Continue + } +} + +fn override_queries( + _sess: &Session, + providers: &mut Providers, + _extern_providers: &mut ExternProviders, +) { + providers.mir_built = |tcx, def: WithOptConstParam| { + let mut providers = Providers::default(); + rustc_mir_build::provide(&mut providers); + + let steal_mir = (providers.mir_built)(tcx, def); + let mut mir = steal_mir.steal(); + + let body_did = def.did.to_def_id(); + let fn_ty = tcx.type_of(body_did); + if fn_ty.is_fn() && !tcx.is_const_fn(body_did) && !tcx.is_static(body_did) { + INSTRUMENTER.instrument_fn(tcx, &mut mir, body_did); + + validate::Validator { + when: "After dynamic instrumentation".to_string(), + mir_phase: mir.phase, + } + .run_pass(tcx, &mut mir); + } + + tcx.alloc_steal_mir(mir) + }; +} From 407d39c49360dde1d0dd6a67532f1f7f1bfe71d5 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:47:07 -0700 Subject: [PATCH 33/50] Removed unused `extern crate rustc_target`. --- dynamic_instrumentation/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 6f5fe7e33f..e111d2386b 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -1,18 +1,18 @@ #![feature(rustc_private)] -extern crate rustc_driver; -extern crate rustc_session; -extern crate rustc_span; extern crate rustc_ast; extern crate rustc_const_eval; extern crate rustc_data_structures; +extern crate rustc_driver; extern crate rustc_index; extern crate rustc_interface; extern crate rustc_middle; extern crate rustc_mir_build; extern crate rustc_mir_transform; -extern crate rustc_target; +extern crate rustc_session; +extern crate rustc_span; mod instrument_memory; + use instrument_memory::InstrumentMemoryOps; use std::{ From e32281cf9a178f29fd4d9aa2df87a62da1695bf3 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 22:49:44 -0700 Subject: [PATCH 34/50] Renamed `c2rust-dynamic-instrumentation` to `c2rust-instrument` so the binary name now matches the old one. --- Cargo.lock | 2 +- dynamic_instrumentation/Cargo.toml | 2 +- scripts/pdg.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bf7a1a954..c339deb125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,7 +228,7 @@ dependencies = [ ] [[package]] -name = "c2rust-dynamic-instrumentation" +name = "c2rust-instrument" version = "0.1.0" dependencies = [ "anyhow", diff --git a/dynamic_instrumentation/Cargo.toml b/dynamic_instrumentation/Cargo.toml index ce9f6a522e..3a80221eef 100644 --- a/dynamic_instrumentation/Cargo.toml +++ b/dynamic_instrumentation/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "c2rust-dynamic-instrumentation" +name = "c2rust-instrument" version = "0.1.0" edition = "2021" diff --git a/scripts/pdg.sh b/scripts/pdg.sh index e79eff7ee7..392ad97e13 100755 --- a/scripts/pdg.sh +++ b/scripts/pdg.sh @@ -35,7 +35,7 @@ main() { fi local profile_args=(--profile "${profile}") - local instrument="c2rust-dynamic-instrumentation" + local instrument="c2rust-instrument" cargo build "${profile_args[@]}" --bin "${instrument}" local c2rust="${CWD}/${profile_dir}/c2rust" From 6595ad8503db4fcf6e17f3d104ebbd92825b4753 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 23:21:33 -0700 Subject: [PATCH 35/50] Now `CARGO_TARGET_DIR=instrument.target` is set so that normal `cargo build` doesn't conflict. --- .gitignore | 1 + dynamic_instrumentation/src/main.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index cf9a415a10..1e236c10b5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.log # ignore rust build dirs everywhere **/target/ +**/instrument.target/ **/tests/ /build *.pyc diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index e111d2386b..8cb39d9be7 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -140,6 +140,9 @@ fn main() -> anyhow::Result<()> { let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + let cargo_target_dir_var = "CARGO_TARGET_DIR"; + let cargo_target_dir = "instrument.target"; + let cargo_metadata = MetadataCommand::new().cargo_path(&cargo).exec()?; let root_package = cargo_metadata @@ -148,6 +151,7 @@ fn main() -> anyhow::Result<()> { let status = Command::new(&cargo) .args(&["clean", "--package", root_package.name.as_str()]) + .env(cargo_target_dir_var, cargo_target_dir) .status()?; if !status.success() { exit_with_status(status); @@ -156,6 +160,7 @@ fn main() -> anyhow::Result<()> { let status = Command::new(&cargo) .args(cargo_args) .env(rustc_wrapper_var, &own_exe) + .env(cargo_target_dir_var, cargo_target_dir) .env(metadata_var, metadata) .status()?; exit_with_status(status); From de3fd2a1aa1b9b1970871f8aefd556831faf25a1 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 23:44:54 -0700 Subject: [PATCH 36/50] Make `c2rust-analysis-rt` an optional dependency in the instrumented crate and then enable that feature in `c2rust-instrument`. Thus, there's no overhead when not instrumenting. --- analysis/test/Cargo.toml | 2 +- dynamic_instrumentation/src/main.rs | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/analysis/test/Cargo.toml b/analysis/test/Cargo.toml index 48cac5dad0..838e8ce06e 100644 --- a/analysis/test/Cargo.toml +++ b/analysis/test/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" [dependencies] libc = "0.2" -c2rust-analysis-rt = { path = "../../analysis/runtime"} +c2rust-analysis-rt = { path = "../../analysis/runtime", optional = true } diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 8cb39d9be7..93023d74d4 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -135,7 +135,7 @@ fn main() -> anyhow::Result<()> { } else { let Args { metadata, - cargo_args, + mut cargo_args, } = Args::parse(); let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); @@ -157,6 +157,23 @@ fn main() -> anyhow::Result<()> { exit_with_status(status); } + // Insert the feature flags as the first arguments following the `cargo` subcommand. + // We can't insert them at the end because they could come after a `--` and thus be ignored. + // And we can't insert them at the beginning before the `cargo` subcommand argument, + // as `--features` is an argument of the subcommands, not `cargo` itself. + let insertion_point = 1; + // If there are no arguments, this would panic on splicing/insertion, + // and we don't want to add the feature flags anyways, as `cargo` without arguments is already an error, + // and we don't want to obfuscate that error with an error about unexpected feature flags. + if cargo_args.len() >= insertion_point { + cargo_args.splice( + insertion_point..insertion_point, + ["--features", "c2rust-analysis-rt"] + .iter() + .map(|s| s.into()), + ); + } + let status = Command::new(&cargo) .args(cargo_args) .env(rustc_wrapper_var, &own_exe) From 56332860c4252ae8372c35aed1d873252b44f007 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Wed, 27 Jul 2022 23:48:12 -0700 Subject: [PATCH 37/50] Extracted `fn add_runtime_feature`. --- dynamic_instrumentation/src/main.rs | 40 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 93023d74d4..b35ce01873 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -99,6 +99,28 @@ fn get_sysroot() -> anyhow::Result { .or_else(|()| get_sysroot_slow()) } +/// Insert the feature flags as the first arguments following the `cargo` subcommand. +/// +/// We can't insert them at the end because they could come after a `--` and thus be ignored. +/// And we can't insert them at the beginning before the `cargo` subcommand argument, +/// as `--features` is an argument of the subcommands, not `cargo` itself. +/// +/// If there are no arguments, we don't insert the feature flags, as: +/// * it would panic on splicing/insertion +/// * we don't want to add the feature flags anyways, as `cargo` without arguments is already an error +/// * we don't want to obfuscate that error with an error about unexpected feature flags +fn add_runtime_feature(cargo_args: &mut Vec) { + let insertion_point = 1; + if cargo_args.len() >= insertion_point { + cargo_args.splice( + insertion_point..insertion_point, + ["--features", "c2rust-analysis-rt"] + .iter() + .map(|s| s.into()), + ); + } +} + fn main() -> anyhow::Result<()> { let rustc_wrapper_var = "RUSTC_WRAPPER"; let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; @@ -157,23 +179,7 @@ fn main() -> anyhow::Result<()> { exit_with_status(status); } - // Insert the feature flags as the first arguments following the `cargo` subcommand. - // We can't insert them at the end because they could come after a `--` and thus be ignored. - // And we can't insert them at the beginning before the `cargo` subcommand argument, - // as `--features` is an argument of the subcommands, not `cargo` itself. - let insertion_point = 1; - // If there are no arguments, this would panic on splicing/insertion, - // and we don't want to add the feature flags anyways, as `cargo` without arguments is already an error, - // and we don't want to obfuscate that error with an error about unexpected feature flags. - if cargo_args.len() >= insertion_point { - cargo_args.splice( - insertion_point..insertion_point, - ["--features", "c2rust-analysis-rt"] - .iter() - .map(|s| s.into()), - ); - } - + add_runtime_feature(&mut cargo_args); let status = Command::new(&cargo) .args(cargo_args) .env(rustc_wrapper_var, &own_exe) From 6bc9906088c3ceac935f8ef19c92fba4352260c6 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 00:00:20 -0700 Subject: [PATCH 38/50] Added a small abstraction around `cargo` invocations to simplify things a bit. --- dynamic_instrumentation/src/main.rs | 67 ++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index b35ce01873..b10ae93f6c 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -121,6 +121,41 @@ fn add_runtime_feature(cargo_args: &mut Vec) { } } +struct Cargo { + path: PathBuf, +} + +impl Cargo { + pub fn new() -> Self { + let path = env::var_os("CARGO") + .unwrap_or_else(|| "cargo".into()) + .into(); + Self { path } + } + + pub fn metadata(&self) -> MetadataCommand { + let mut cmd = MetadataCommand::new(); + cmd.cargo_path(&self.path); + cmd + } + + pub fn command(&self) -> Command { + let mut cmd = Command::new(&self.path); + cmd.env("CARGO_TARGET_DIR", "instrument.target"); + cmd + } + + pub fn run(&self, f: impl FnOnce(&mut Command)) -> anyhow::Result<()> { + let mut cmd = self.command(); + f(&mut cmd); + let status = cmd.status()?; + if !status.success() { + exit_with_status(status); + } + Ok(()) + } +} + fn main() -> anyhow::Result<()> { let rustc_wrapper_var = "RUSTC_WRAPPER"; let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; @@ -160,33 +195,23 @@ fn main() -> anyhow::Result<()> { mut cargo_args, } = Args::parse(); - let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); - - let cargo_target_dir_var = "CARGO_TARGET_DIR"; - let cargo_target_dir = "instrument.target"; - - let cargo_metadata = MetadataCommand::new().cargo_path(&cargo).exec()?; + let cargo = Cargo::new(); + let cargo_metadata = cargo.metadata().exec()?; let root_package = cargo_metadata .root_package() .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; - let status = Command::new(&cargo) - .args(&["clean", "--package", root_package.name.as_str()]) - .env(cargo_target_dir_var, cargo_target_dir) - .status()?; - if !status.success() { - exit_with_status(status); - } + cargo.run(|cmd| { + cmd.args(&["clean", "--package", root_package.name.as_str()]); + })?; - add_runtime_feature(&mut cargo_args); - let status = Command::new(&cargo) - .args(cargo_args) - .env(rustc_wrapper_var, &own_exe) - .env(cargo_target_dir_var, cargo_target_dir) - .env(metadata_var, metadata) - .status()?; - exit_with_status(status); + cargo.run(|cmd| { + add_runtime_feature(&mut cargo_args); + cmd.args(cargo_args) + .env(rustc_wrapper_var, &own_exe) + .env(metadata_var, metadata); + })?; } Ok(()) } From 6265cfa1f8d0e52883d4475a62d01d5fe9599d1b Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 00:26:34 -0700 Subject: [PATCH 39/50] Removed `$RUST_SYSROOT` code as it's no longer used anywhere. --- dynamic_instrumentation/build.rs | 1 - rustc-private-link/src/lib.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/dynamic_instrumentation/build.rs b/dynamic_instrumentation/build.rs index b873c077eb..9bbd6765ac 100644 --- a/dynamic_instrumentation/build.rs +++ b/dynamic_instrumentation/build.rs @@ -2,7 +2,6 @@ use rustc_private_link::SysRoot; fn main() { let sysroot = SysRoot::resolve(); - sysroot.set_env_rust_sysroot(); // Not strictly needed here since this is not used as this is a library crate (it's needed in `c2rust`), // but it doesn't hurt, and in case this ever adds a binary crate, it's useful. sysroot.link_rustc_private(); diff --git a/rustc-private-link/src/lib.rs b/rustc-private-link/src/lib.rs index 68a6192649..407cdde5da 100644 --- a/rustc-private-link/src/lib.rs +++ b/rustc-private-link/src/lib.rs @@ -65,10 +65,6 @@ impl SysRoot { .collect() } - pub fn set_env_rust_sysroot(&self) { - print_cargo_path("rustc-env=RUST_SYSROOT=", self.sysroot()); - } - pub fn link_rustc_private(&self) { let lib = self.lib(); print_cargo_path("rustc-link-search=native=", &lib); From 628266b0ca0cb7347ff981d6e806d36db41f347c Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 00:35:40 -0700 Subject: [PATCH 40/50] Implemented `get_sysroot_slow` using `rustc --print sysroot` (copied from `rustc_private_link::SysRoot::resolve`, but with `anyhow` instead of `.expect(...)`s). --- dynamic_instrumentation/src/main.rs | 32 ++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index b10ae93f6c..c0c49881db 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -17,7 +17,7 @@ use instrument_memory::InstrumentMemoryOps; use std::{ env, - ffi::OsString, + ffi::{OsStr, OsString}, path::{Path, PathBuf}, process::{self, Command, ExitStatus}, }; @@ -38,7 +38,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; @@ -60,6 +60,7 @@ fn exit_with_status(status: ExitStatus) { process::exit(status.code().unwrap_or(1)) } +/// Lookup the sysroot fast using `rustup` environment variables. fn get_sysroot_fast() -> Option { let sysroot = [ env::var_os("RUSTUP_HOME")?, @@ -71,8 +72,33 @@ fn get_sysroot_fast() -> Option { Some(sysroot) } +/// Lookup the sysroot slow, but in a more reliable way using `rustc --print sysroot`. +/// +/// TODO(kkysen) deduplicate this with `rustc_private_link::SysRoot::resolve` fn get_sysroot_slow() -> anyhow::Result { - todo!("use `rustc --print sysroot` to support non-`rustup` cases, which @fw-immunant uses") + let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); + let output = Command::new(rustc) + .args(&["--print", "sysroot"]) + .output() + .context("could not invoke `rustc` to find rust sysroot")?; + // trim, but `str::trim` doesn't exist on `[u8]` + let path = output + .stdout + .as_slice() + .split(|c| c.is_ascii_whitespace()) + .next() + .unwrap_or_default(); + let path = if cfg!(unix) { + use std::os::unix::ffi::OsStrExt; + + OsStr::from_bytes(path) + } else { + // Windows is hard, so just require UTF-8 + let path = std::str::from_utf8(path).context("`rustc --print sysroot` is not UTF-8")?; + OsStr::new(path) + }; + let path = Path::new(path).to_owned(); + Ok(path) } /// Resolve the current `rustc` sysroot. From ee163e1376b6dc109e3634ef249a0881ca68306e Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 00:45:44 -0700 Subject: [PATCH 41/50] Extracted `rustc_wrapper` and `cargo_wrapper` into separate functions. --- dynamic_instrumentation/src/main.rs | 113 +++++++++++++++------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index c0c49881db..4eed699797 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -182,64 +182,73 @@ impl Cargo { } } -fn main() -> anyhow::Result<()> { - let rustc_wrapper_var = "RUSTC_WRAPPER"; - let metadata_var = "C2RUST_INSTRUMENT_METADATA_PATH"; +const RUSTC_WRAPPER_VAR: &str = "RUSTC_WRAPPER"; +const METADATA_VAR: &str = "C2RUST_INSTRUMENT_METADATA_PATH"; + +fn rustc_wrapper() -> anyhow::Result<()> { + let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); + let should_instrument = is_primary_package; + let mut at_args = env::args().skip(1).collect::>(); + let sysroot = get_sysroot()?; + let sysroot: &Utf8Path = sysroot.as_path().try_into()?; + at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); + let result = if should_instrument { + RunCompiler::new(&at_args, &mut MirTransformCallbacks).run() + } else { + // Always use the dynamically linked `librustc_driver-{hash}.so`, + // as it is guaranteed to be the same version as the instrumented version. + // Furthermore, we can't accidentally load the wrong `librustc_driver-{hash}.so`, + // as it contains its hash. + // This also avoids an extra `rustc` (and potentially `rustup` `rustc`) invocation. + RunCompiler::new(&at_args, &mut TimePassesCallbacks::default()).run() + }; + // `ErrorReported` means the error has already been reported to the user, + // so we just have to fail/exit with a failing exit code. + // There is no `impl Error for ErrorReported`. + result.map_err(|_| anyhow!("`rustc` failed"))?; + if should_instrument { + let metadata = env::var_os(METADATA_VAR).ok_or_else(|| anyhow!("we should've set this"))?; + INSTRUMENTER.finalize(Path::new(&metadata))?; + } + Ok(()) +} + +fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> { + let Args { + metadata, + mut cargo_args, + } = Args::parse(); + + let cargo = Cargo::new(); + + let cargo_metadata = cargo.metadata().exec()?; + let root_package = cargo_metadata + .root_package() + .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; + cargo.run(|cmd| { + cmd.args(&["clean", "--package", root_package.name.as_str()]); + })?; + + cargo.run(|cmd| { + add_runtime_feature(&mut cargo_args); + cmd.args(cargo_args) + .env(RUSTC_WRAPPER_VAR, rustc_wrapper) + .env(METADATA_VAR, metadata); + })?; + + Ok(()) +} + +fn main() -> anyhow::Result<()> { let own_exe = env::current_exe()?; - let wrapping_rustc = env::var_os(rustc_wrapper_var).as_deref() == Some(own_exe.as_os_str()); + let wrapping_rustc = env::var_os(RUSTC_WRAPPER_VAR).as_deref() == Some(own_exe.as_os_str()); if wrapping_rustc { - let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - let should_instrument = is_primary_package; - let mut at_args = env::args().skip(1).collect::>(); - let sysroot = get_sysroot()?; - let sysroot: &Utf8Path = sysroot.as_path().try_into()?; - at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); - let result = if should_instrument { - RunCompiler::new(&at_args, &mut MirTransformCallbacks).run() - } else { - // Always use the dynamically linked `librustc_driver-{hash}.so`, - // as it is guaranteed to be the same version as the instrumented version. - // Furthermore, we can't accidentally load the wrong `librustc_driver-{hash}.so`, - // as it contains its hash. - // This also avoids an extra `rustc` (and potentially `rustup` `rustc`) invocation. - RunCompiler::new(&at_args, &mut TimePassesCallbacks::default()).run() - }; - // `ErrorReported` means the error has already been reported to the user, - // so we just have to fail/exit with a failing exit code. - // There is no `impl Error for ErrorReported`. - result.map_err(|_| anyhow!("`rustc` failed"))?; - if should_instrument { - let metadata = - env::var_os(metadata_var).ok_or_else(|| anyhow!("we should've set this"))?; - INSTRUMENTER.finalize(Path::new(&metadata))?; - } + rustc_wrapper() } else { - let Args { - metadata, - mut cargo_args, - } = Args::parse(); - - let cargo = Cargo::new(); - - let cargo_metadata = cargo.metadata().exec()?; - let root_package = cargo_metadata - .root_package() - .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; - - cargo.run(|cmd| { - cmd.args(&["clean", "--package", root_package.name.as_str()]); - })?; - - cargo.run(|cmd| { - add_runtime_feature(&mut cargo_args); - cmd.args(cargo_args) - .env(rustc_wrapper_var, &own_exe) - .env(metadata_var, metadata); - })?; + cargo_wrapper(&own_exe) } - Ok(()) } lazy_static! { From d1997b4a5fa58c4c5f7e0f499a0bf133245b2b8a Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 00:57:02 -0700 Subject: [PATCH 42/50] Don't need to link to `rustc` private crates in `c2rust` anymore (since `c2rust-instrument` is now separated), and don't need the `build.rs` at all anymore. --- c2rust/build.rs | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 c2rust/build.rs diff --git a/c2rust/build.rs b/c2rust/build.rs deleted file mode 100644 index 3d93932b5e..0000000000 --- a/c2rust/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -use rustc_private_link::SysRoot; - -fn main() { - let sysroot = SysRoot::resolve(); - sysroot.link_rustc_private(); -} From c1a95e236d0b0e4b997398d0f92a903c04635bfc Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 22:47:03 -0700 Subject: [PATCH 43/50] Print the command if a `cargo` invocation fails. --- dynamic_instrumentation/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 4eed699797..5f32196694 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -176,6 +176,7 @@ impl Cargo { f(&mut cmd); let status = cmd.status()?; if !status.success() { + eprintln!("error running: {cmd:?}"); exit_with_status(status); } Ok(()) From 3012d4655ab943a96413b4b624380c2ec56e195b Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Thu, 28 Jul 2022 23:14:10 -0700 Subject: [PATCH 44/50] Set `RUSTUP_TOOLCHAIN=$(cat rust-toolchain)` so that we always use the same toolchain as the `rustc` we built with. --- dynamic_instrumentation/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 5f32196694..73b4f2006a 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -167,7 +167,8 @@ impl Cargo { pub fn command(&self) -> Command { let mut cmd = Command::new(&self.path); - cmd.env("CARGO_TARGET_DIR", "instrument.target"); + cmd.env("RUSTUP_TOOLCHAIN", include_str!("../rust-toolchain").trim()) + .env("CARGO_TARGET_DIR", "instrument.target"); cmd } From 657cf2428ecc0e3aa92953e30d0446fc18166013 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sat, 30 Jul 2022 00:46:12 -0700 Subject: [PATCH 45/50] Now we resolve the sysroot in the `cargo` wrapper and pass it to the `rustc` wrapper through `$RUST_SYSROOT`. Furthermore, we only use `rustc --print sysroot`, not `$RUSTUP_HOME/toolchains/$RUSTUP_TOOLCHAIN`, as that's incorrect when we set `$RUSTUP_TOOLCHAIN` ourselves, and they aren't set in the `cargo` wrapper. --- dynamic_instrumentation/src/main.rs | 87 ++++++++++++++--------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 8031b31419..ec7fb5dc6d 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -43,7 +43,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; -use anyhow::{anyhow, Context}; +use anyhow::{anyhow, ensure, Context}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; @@ -67,22 +67,27 @@ fn exit_with_status(status: ExitStatus) { process::exit(status.code().unwrap_or(1)) } -/// Lookup the sysroot fast using `rustup` environment variables. -fn get_sysroot_fast() -> Option { - let sysroot = [ - env::var_os("RUSTUP_HOME")?, - "toolchains".into(), - env::var_os("RUSTUP_TOOLCHAIN")?, - ] - .into_iter() - .collect(); - Some(sysroot) -} - -/// Lookup the sysroot slow, but in a more reliable way using `rustc --print sysroot`. +/// Resolve the current `rustc` sysroot using `rustc --print sysroot`. +/// +/// Normally, `rustc` looks up the sysroot by the location of its own binary. +/// This works because the `rustc` on `$PATH` is actually `rustup`, +/// and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. +/// As we invoke `rustc_driver` directly here, we are `rustc`, +/// and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. +/// +/// Note that the sysroot contains the toolchain and host target name, +/// but this has no effect on cross-compiling. +/// Every toolchain's `rustc` is able to itself cross-compile. +/// I'm not sure why the host target needs to be in the sysroot directory name, but it is. +/// +/// Also note that this sysroot lookup should be done at runtime, +/// not at compile-time in the `build.rs`, +/// as the toolchain locations could be different +/// from where this binary was compiled and where it is running +/// (it could be on a different machine with a different `$RUSTUP_HOME`). /// /// TODO(kkysen) deduplicate this with `rustc_private_link::SysRoot::resolve` -fn get_sysroot_slow() -> anyhow::Result { +fn resolve_sysroot() -> anyhow::Result { let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); let output = Command::new(rustc) .args(&["--print", "sysroot"]) @@ -105,33 +110,15 @@ fn get_sysroot_slow() -> anyhow::Result { OsStr::new(path) }; let path = Path::new(path).to_owned(); + // `rustc` reports a million errors if the sysroot is wrong, so try to check first. + ensure!( + path.is_dir(), + "invalid sysroot (not a dir): {}", + path.display() + ); Ok(path) } -/// Resolve the current `rustc` sysroot. -/// -/// Normally, `rustc` looks up the sysroot by the location of its own binary. -/// This works because the `rustc` on `$PATH` is actually `rustup`, -/// and `rustup` invokes the real `rustc`, which is in a location relative to the sysroot. -/// As we invoke `rustc_driver` directly here, we are `rustc`, -/// and thus we have to explicitly specify the sysroot that the real `rustc` would normally use. -/// -/// Note that the sysroot contains the toolchain and host target name, -/// but this has no effect on cross-compiling. -/// Every toolchain's `rustc` is able to itself cross-compile. -/// I'm not sure why the host target needs to be in the sysroot directory name, but it is. -/// -/// Also note that this sysroot lookup should be done at runtime, -/// not at compile-time in the `build.rs`, -/// as the toolchain locations could be different -/// from where this binary was compiled and where it is running -/// (it could be on a different machine with a different `$RUSTUP_HOME`). -fn get_sysroot() -> anyhow::Result { - get_sysroot_fast() - .ok_or(()) - .or_else(|()| get_sysroot_slow()) -} - /// Insert the feature flags as the first arguments following the `cargo` subcommand. /// /// We can't insert them at the end because they could come after a `--` and thus be ignored. @@ -174,8 +161,7 @@ impl Cargo { pub fn command(&self) -> Command { let mut cmd = Command::new(&self.path); - cmd.env("RUSTUP_TOOLCHAIN", include_str!("../rust-toolchain").trim()) - .env("CARGO_TARGET_DIR", "instrument.target"); + cmd.env("CARGO_TARGET_DIR", "instrument.target"); cmd } @@ -192,13 +178,20 @@ impl Cargo { } const RUSTC_WRAPPER_VAR: &str = "RUSTC_WRAPPER"; +const RUST_SYSROOT_VAR: &str = "RUST_SYSROOT"; const METADATA_VAR: &str = "C2RUST_INSTRUMENT_METADATA_PATH"; +fn env_path_from_wrapper(var: &str) -> anyhow::Result { + let path = env::var_os(var) + .ok_or_else(|| anyhow!("the `cargo` wrapper should've `${var}` for the `rustc` wrapper"))?; + Ok(path.into()) +} + fn rustc_wrapper() -> anyhow::Result<()> { let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); let should_instrument = is_primary_package; let mut at_args = env::args().skip(1).collect::>(); - let sysroot = get_sysroot()?; + let sysroot = env_path_from_wrapper(RUST_SYSROOT_VAR)?; let sysroot: &Utf8Path = sysroot.as_path().try_into()?; at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); let result = if should_instrument { @@ -216,8 +209,7 @@ fn rustc_wrapper() -> anyhow::Result<()> { // There is no `impl Error for ErrorReported`. result.map_err(|_| anyhow!("`rustc` failed"))?; if should_instrument { - let metadata = env::var_os(METADATA_VAR).ok_or_else(|| anyhow!("we should've set this"))?; - INSTRUMENTER.finalize(Path::new(&metadata))?; + INSTRUMENTER.finalize(&env_path_from_wrapper(METADATA_VAR)?)?; } Ok(()) } @@ -228,6 +220,10 @@ fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> { mut cargo_args, } = Args::parse(); + env::set_var("RUSTUP_TOOLCHAIN", include_str!("../rust-toolchain").trim()); + + let sysroot = resolve_sysroot()?; + let cargo = Cargo::new(); let cargo_metadata = cargo.metadata().exec()?; @@ -243,7 +239,8 @@ fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> { add_runtime_feature(&mut cargo_args); cmd.args(cargo_args) .env(RUSTC_WRAPPER_VAR, rustc_wrapper) - .env(METADATA_VAR, metadata); + .env(RUST_SYSROOT_VAR, &sysroot) + .env(METADATA_VAR, &metadata); })?; Ok(()) From 5ce75c4ab19b974695c6248a4b134b86f402f2cc Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sat, 30 Jul 2022 00:51:17 -0700 Subject: [PATCH 46/50] Simplified an import. --- dynamic_instrumentation/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index ec7fb5dc6d..836628bdab 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -30,7 +30,7 @@ use std::{ use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; use rustc_ast::node_id::NodeId; use rustc_ast::ptr::P; -use rustc_const_eval::transform::validate; +use rustc_const_eval::transform::validate::Validator; use rustc_driver::Compilation; use rustc_driver::{RunCompiler, TimePassesCallbacks}; use rustc_interface::interface::Compiler; @@ -310,7 +310,7 @@ fn override_queries( if fn_ty.is_fn() && !tcx.is_const_fn(body_did) && !tcx.is_static(body_did) { INSTRUMENTER.instrument_fn(tcx, &mut mir, body_did); - validate::Validator { + Validator { when: "After dynamic instrumentation".to_string(), mir_phase: mir.phase, } From 26609468d6d4c8102139210fdc94891f59b02eca Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sat, 30 Jul 2022 01:34:33 -0700 Subject: [PATCH 47/50] Don't instrument build scripts. `lighttpd` was failing to be instrumented because we tried to instrument its build script, since `$CARGO_PRIMARY_PACKAGE` is set for it. We can't instrument build scripts because `c2rust-analysis-rt` is not yet built for them, and running the build script would then fail because environment variables needed by the runtime may not be set. And we don't want to instrument the build scripts because they're at compile time. To detect this, we check for when `--crate-type bin` is specified (using `rustc_driver`'s arg-parsing code) and yet there's also no `$CARGO_BIN_NAME`, which is set for normal binary crates. --- dynamic_instrumentation/src/main.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 836628bdab..645ba44883 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -38,7 +38,7 @@ use rustc_interface::Queries; use rustc_middle::mir::MirPass; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::WithOptConstParam; -use rustc_session::Session; +use rustc_session::{Session, config::CrateType}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::DUMMY_SP; @@ -187,10 +187,33 @@ fn env_path_from_wrapper(var: &str) -> anyhow::Result { Ok(path.into()) } +fn is_primary_package() -> bool { + env::var("CARGO_PRIMARY_PACKAGE").is_ok() +} + +fn is_bin_crate(at_args: &[String]) -> anyhow::Result { + let args = rustc_driver::args::arg_expand_all(at_args); + let matches = rustc_driver::handle_options(&args) + .ok_or_else(|| anyhow!("failed to parse `rustc` args"))?; + let session_options = rustc_session::config::build_session_options(&matches); + let is_bin = session_options.crate_types.contains(&CrateType::Executable); + Ok(is_bin) +} + +fn bin_crate_name() -> Option { + env::var_os("CARGO_BIN_NAME").map(PathBuf::from) +} + +fn is_build_script(at_args: &[String]) -> anyhow::Result { + Ok(bin_crate_name().is_none() && is_bin_crate(at_args)?) +} + fn rustc_wrapper() -> anyhow::Result<()> { - let is_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - let should_instrument = is_primary_package; let mut at_args = env::args().skip(1).collect::>(); + // `c2rust-analysis-rt` is not yet built for the build script, + // so trying to compile it will fail. + // Plus, we don't need to and don't want to instrument the build script. + let should_instrument = is_primary_package() && !is_build_script(&at_args)?; let sysroot = env_path_from_wrapper(RUST_SYSROOT_VAR)?; let sysroot: &Utf8Path = sysroot.as_path().try_into()?; at_args.extend(["--sysroot".into(), sysroot.as_str().into()]); From 93f88db92d6cc91b6aa2a2880f483ea19f5e0565 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 1 Aug 2022 15:13:50 -0700 Subject: [PATCH 48/50] Added documentation for why we use the current build script detection solution vs. the `--target` one used by `miri`, et. al. --- dynamic_instrumentation/src/main.rs | 37 ++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 645ba44883..1ba0f0787e 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -204,15 +204,46 @@ fn bin_crate_name() -> Option { env::var_os("CARGO_BIN_NAME").map(PathBuf::from) } +/// Detect if the `rustc` invocation is for compiling a build script. +/// +/// `c2rust-analysis-rt` is not yet built for the build script, +/// so trying to compile it will fail. +/// Plus, we don't need to and don't want to instrument the build script. +/// +/// We check if it is a build script by checking if it's a `--crate-type bin` +/// and yet has no `$CARGO_BIN_NAME`, which is set for normal binary crates. +/// +/// Another solution (that `miri` uses) is to always specify the `--target`, +/// even if it's the host target. Then `cargo` thinks it's cross-compiling, +/// and always forwards `--target` to `rustc` for native compilations, +/// but for host compilations like build scripts and proc-macros, +/// it doesn't specify `--target`. +/// +/// This would work more robustly if we were also instrumenting dependencies, +/// as our currently solution would no longer work, but we aren't. +/// +/// On the other hand, the `--target` solution has a drawback +/// in that there are many ways to specify the target: +/// * `--target` +/// * `$CARGO_BUILD_TARGET` +/// * `targets` in `rust-toolchain.toml` +/// * `targets` in `.cargo/config.toml` +/// * and maybe some other places as well +/// All the resolution is in `cargo`, but we have to decide +/// if we're going to supply `--target $HOST` before `cargo` runs, +/// so we have to check all of those places ourselves to make sure +/// that we're not overriding the true cross-compilation the user wants. +/// +/// Compared to the current solution, this seems harder, +/// so we're sticking with the current solution for now as long as it works. fn is_build_script(at_args: &[String]) -> anyhow::Result { Ok(bin_crate_name().is_none() && is_bin_crate(at_args)?) } fn rustc_wrapper() -> anyhow::Result<()> { let mut at_args = env::args().skip(1).collect::>(); - // `c2rust-analysis-rt` is not yet built for the build script, - // so trying to compile it will fail. - // Plus, we don't need to and don't want to instrument the build script. + // We also want to avoid proc-macro crates, + // but those must be separate crates, so we should be okay. let should_instrument = is_primary_package() && !is_build_script(&at_args)?; let sysroot = env_path_from_wrapper(RUST_SYSROOT_VAR)?; let sysroot: &Utf8Path = sysroot.as_path().try_into()?; From 5abd6d656d61caf565927b4f3faa3d342a0e696a Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 1 Aug 2022 15:41:05 -0700 Subject: [PATCH 49/50] Added more thorough documentation. --- dynamic_instrumentation/src/main.rs | 38 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 1ba0f0787e..6ed59b7d14 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -24,7 +24,7 @@ use std::{ env, ffi::{OsStr, OsString}, path::{Path, PathBuf}, - process::{self, Command, ExitStatus}, + process::{self, Command, ExitStatus}, iter, }; use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; @@ -119,7 +119,7 @@ fn resolve_sysroot() -> anyhow::Result { Ok(path) } -/// Insert the feature flags as the first arguments following the `cargo` subcommand. +/// Insert feature flags as the first arguments following the `cargo` subcommand. /// /// We can't insert them at the end because they could come after a `--` and thus be ignored. /// And we can't insert them at the beginning before the `cargo` subcommand argument, @@ -129,13 +129,12 @@ fn resolve_sysroot() -> anyhow::Result { /// * it would panic on splicing/insertion /// * we don't want to add the feature flags anyways, as `cargo` without arguments is already an error /// * we don't want to obfuscate that error with an error about unexpected feature flags -fn add_runtime_feature(cargo_args: &mut Vec) { +fn add_feature(cargo_args: &mut Vec, features: &[&str]) { let insertion_point = 1; if cargo_args.len() >= insertion_point { cargo_args.splice( insertion_point..insertion_point, - ["--features", "c2rust-analysis-rt"] - .iter() + iter::once(&"--features").chain(features) .map(|s| s.into()), ); } @@ -181,16 +180,24 @@ const RUSTC_WRAPPER_VAR: &str = "RUSTC_WRAPPER"; const RUST_SYSROOT_VAR: &str = "RUST_SYSROOT"; const METADATA_VAR: &str = "C2RUST_INSTRUMENT_METADATA_PATH"; +/// Read a [`PathBuf`] from the [`mod@env`]ironment that should've been set by the [`cargo_wrapper`]. fn env_path_from_wrapper(var: &str) -> anyhow::Result { let path = env::var_os(var) .ok_or_else(|| anyhow!("the `cargo` wrapper should've `${var}` for the `rustc` wrapper"))?; Ok(path.into()) } +/// Check if the current [`rustc_wrapper`] invocation is for the primary `cargo` package, +/// as determined by `$CARGO_PRIMARY_PACKAGE`. fn is_primary_package() -> bool { env::var("CARGO_PRIMARY_PACKAGE").is_ok() } +/// Check if the current [`rustc_wrapper`] invocation is a binary crate, +/// i.e., if `--crate-type bin` was specified. +/// +/// This uses the [`rustc_driver`] and [`rustc_session`] APIs +/// to check this exactly as `rustc` would. fn is_bin_crate(at_args: &[String]) -> anyhow::Result { let args = rustc_driver::args::arg_expand_all(at_args); let matches = rustc_driver::handle_options(&args) @@ -200,11 +207,16 @@ fn is_bin_crate(at_args: &[String]) -> anyhow::Result { Ok(is_bin) } +/// Read the name of the current binary crate being compiled, if it is a binary crate ([`is_bin_crate`]). +/// +/// Note that despite setting `--crate-type bin` and [`is_bin_crate`] being true, +/// there is no name set for build scripts. +/// That's how we can detect them. fn bin_crate_name() -> Option { env::var_os("CARGO_BIN_NAME").map(PathBuf::from) } -/// Detect if the `rustc` invocation is for compiling a build script. +/// Detect if the current [`rustc_wrapper`] is for compiling a build script. /// /// `c2rust-analysis-rt` is not yet built for the build script, /// so trying to compile it will fail. @@ -240,6 +252,7 @@ fn is_build_script(at_args: &[String]) -> anyhow::Result { Ok(bin_crate_name().is_none() && is_bin_crate(at_args)?) } +/// Run as a `rustc` wrapper (a la `$RUSTC_WRAPPER`/[`RUSTC_WRAPPER_VAR`]). fn rustc_wrapper() -> anyhow::Result<()> { let mut at_args = env::args().skip(1).collect::>(); // We also want to avoid proc-macro crates, @@ -268,14 +281,18 @@ fn rustc_wrapper() -> anyhow::Result<()> { Ok(()) } +/// Run as a `cargo` wrapper/plugin, the default invocation. fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> { let Args { metadata, mut cargo_args, } = Args::parse(); + // Ensure we use a toolchain compatible with the `rustc` private crates we linked to. env::set_var("RUSTUP_TOOLCHAIN", include_str!("../rust-toolchain").trim()); + // Resolve the sysroot once in the [`cargo_wrapper`] + // so that we don't need all of the [`rustc_wrapper`]s to have to do it. let sysroot = resolve_sysroot()?; let cargo = Cargo::new(); @@ -286,11 +303,18 @@ fn cargo_wrapper(rustc_wrapper: &Path) -> anyhow::Result<()> { .ok_or_else(|| anyhow!("no root package found by `cargo`"))?; cargo.run(|cmd| { + // Clean the primary package so that we always rebuild it + // and get up-to-date, complete instrumentation [`Metadata`]. + // Incremental instrumentation is very tricky, + // so don't try that yet, + // and if we only need to rebuild the primary package, + // it usually isn't that slow. cmd.args(&["clean", "--package", root_package.name.as_str()]); })?; cargo.run(|cmd| { - add_runtime_feature(&mut cargo_args); + // Enable the runtime dependency. + add_feature(&mut cargo_args, &["c2rust-analysis-rt"]); cmd.args(cargo_args) .env(RUSTC_WRAPPER_VAR, rustc_wrapper) .env(RUST_SYSROOT_VAR, &sysroot) From d99b9a8dea579ca4d20a4421deea17489a18ff04 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Tue, 2 Aug 2022 16:19:53 -0700 Subject: [PATCH 50/50] Move the previous `lib.rs` code in `main.rs` to `callbacks.rs` for a (hopefully) cleaner diff. --- dynamic_instrumentation/src/callbacks.rs | 82 +++++++++++++++++ dynamic_instrumentation/src/main.rs | 107 ++++------------------- 2 files changed, 97 insertions(+), 92 deletions(-) create mode 100644 dynamic_instrumentation/src/callbacks.rs diff --git a/dynamic_instrumentation/src/callbacks.rs b/dynamic_instrumentation/src/callbacks.rs new file mode 100644 index 0000000000..b27542514d --- /dev/null +++ b/dynamic_instrumentation/src/callbacks.rs @@ -0,0 +1,82 @@ +use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; +use rustc_ast::node_id::NodeId; +use rustc_ast::ptr::P; +use rustc_const_eval::transform::validate::Validator; +use rustc_driver::Compilation; +use rustc_interface::interface::Compiler; +use rustc_interface::Queries; +use rustc_middle::mir::MirPass; +use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::ty::WithOptConstParam; +use rustc_session::Session; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; + +use lazy_static::lazy_static; + +use crate::instrument::Instrumenter; + +lazy_static! { + /// TODO(kkysen) can be made non-lazy when `Mutex::new` is `const` in rust 1.63 + pub static ref INSTRUMENTER: Instrumenter = Instrumenter::new(); +} + +pub struct MirTransformCallbacks; + +impl rustc_driver::Callbacks for MirTransformCallbacks { + fn config(&mut self, config: &mut rustc_interface::Config) { + config.override_queries = Some(override_queries); + } + + fn after_parsing<'tcx>( + &mut self, + _compiler: &Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { + let parse = queries.parse().unwrap(); + let mut parse = parse.peek_mut(); + parse.items.push(P(Item { + attrs: Vec::new(), + id: NodeId::from_u32(0), + span: DUMMY_SP, + vis: Visibility { + kind: VisibilityKind::Inherited, + span: DUMMY_SP, + tokens: None, + }, + ident: Ident::from_str("c2rust_analysis_rt"), + kind: ItemKind::ExternCrate(None), + tokens: None, + })); + Compilation::Continue + } +} + +fn override_queries( + _sess: &Session, + providers: &mut Providers, + _extern_providers: &mut ExternProviders, +) { + providers.mir_built = |tcx, def: WithOptConstParam| { + let mut providers = Providers::default(); + rustc_mir_build::provide(&mut providers); + + let steal_mir = (providers.mir_built)(tcx, def); + let mut mir = steal_mir.steal(); + + let body_did = def.did.to_def_id(); + let fn_ty = tcx.type_of(body_did); + if fn_ty.is_fn() && !tcx.is_const_fn(body_did) && !tcx.is_static(body_did) { + INSTRUMENTER.instrument_fn(tcx, &mut mir, body_did); + + Validator { + when: "After dynamic instrumentation".to_string(), + mir_phase: mir.phase, + } + .run_pass(tcx, &mut mir); + } + + tcx.alloc_steal_mir(mir) + }; +} diff --git a/dynamic_instrumentation/src/main.rs b/dynamic_instrumentation/src/main.rs index 6ed59b7d14..36be1a88b5 100644 --- a/dynamic_instrumentation/src/main.rs +++ b/dynamic_instrumentation/src/main.rs @@ -12,6 +12,7 @@ extern crate rustc_session; extern crate rustc_span; mod arg; +mod callbacks; mod hooks; mod instrument; mod into_operand; @@ -20,36 +21,23 @@ mod point; mod runtime_conversions; mod util; +use crate::callbacks::{MirTransformCallbacks, INSTRUMENTER}; + use std::{ env, ffi::{OsStr, OsString}, + iter, path::{Path, PathBuf}, - process::{self, Command, ExitStatus}, iter, + process::{self, Command, ExitStatus}, }; -use rustc_ast::ast::{Item, ItemKind, Visibility, VisibilityKind}; -use rustc_ast::node_id::NodeId; -use rustc_ast::ptr::P; -use rustc_const_eval::transform::validate::Validator; -use rustc_driver::Compilation; use rustc_driver::{RunCompiler, TimePassesCallbacks}; -use rustc_interface::interface::Compiler; -use rustc_interface::Queries; -use rustc_middle::mir::MirPass; -use rustc_middle::ty::query::{ExternProviders, Providers}; -use rustc_middle::ty::WithOptConstParam; -use rustc_session::{Session, config::CrateType}; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::Ident; -use rustc_span::DUMMY_SP; +use rustc_session::config::CrateType; use anyhow::{anyhow, ensure, Context}; use camino::Utf8Path; use cargo_metadata::MetadataCommand; use clap::Parser; -use lazy_static::lazy_static; - -use instrument::Instrumenter; /// Instrument memory accesses for dynamic analysis. #[derive(Debug, Parser)] @@ -134,8 +122,7 @@ fn add_feature(cargo_args: &mut Vec, features: &[&str]) { if cargo_args.len() >= insertion_point { cargo_args.splice( insertion_point..insertion_point, - iter::once(&"--features").chain(features) - .map(|s| s.into()), + iter::once(&"--features").chain(features).map(|s| s.into()), ); } } @@ -195,7 +182,7 @@ fn is_primary_package() -> bool { /// Check if the current [`rustc_wrapper`] invocation is a binary crate, /// i.e., if `--crate-type bin` was specified. -/// +/// /// This uses the [`rustc_driver`] and [`rustc_session`] APIs /// to check this exactly as `rustc` would. fn is_bin_crate(at_args: &[String]) -> anyhow::Result { @@ -208,7 +195,7 @@ fn is_bin_crate(at_args: &[String]) -> anyhow::Result { } /// Read the name of the current binary crate being compiled, if it is a binary crate ([`is_bin_crate`]). -/// +/// /// Note that despite setting `--crate-type bin` and [`is_bin_crate`] being true, /// there is no name set for build scripts. /// That's how we can detect them. @@ -217,23 +204,23 @@ fn bin_crate_name() -> Option { } /// Detect if the current [`rustc_wrapper`] is for compiling a build script. -/// +/// /// `c2rust-analysis-rt` is not yet built for the build script, /// so trying to compile it will fail. /// Plus, we don't need to and don't want to instrument the build script. -/// +/// /// We check if it is a build script by checking if it's a `--crate-type bin` /// and yet has no `$CARGO_BIN_NAME`, which is set for normal binary crates. -/// +/// /// Another solution (that `miri` uses) is to always specify the `--target`, /// even if it's the host target. Then `cargo` thinks it's cross-compiling, /// and always forwards `--target` to `rustc` for native compilations, /// but for host compilations like build scripts and proc-macros, /// it doesn't specify `--target`. -/// +/// /// This would work more robustly if we were also instrumenting dependencies, /// as our currently solution would no longer work, but we aren't. -/// +/// /// On the other hand, the `--target` solution has a drawback /// in that there are many ways to specify the target: /// * `--target` @@ -245,7 +232,7 @@ fn bin_crate_name() -> Option { /// if we're going to supply `--target $HOST` before `cargo` runs, /// so we have to check all of those places ourselves to make sure /// that we're not overriding the true cross-compilation the user wants. -/// +/// /// Compared to the current solution, this seems harder, /// so we're sticking with the current solution for now as long as it works. fn is_build_script(at_args: &[String]) -> anyhow::Result { @@ -334,67 +321,3 @@ fn main() -> anyhow::Result<()> { cargo_wrapper(&own_exe) } } - -lazy_static! { - /// TODO(kkysen) can be made non-lazy when `Mutex::new` is `const` in rust 1.63 - static ref INSTRUMENTER: Instrumenter = Instrumenter::new(); -} - -struct MirTransformCallbacks; - -impl rustc_driver::Callbacks for MirTransformCallbacks { - fn config(&mut self, config: &mut rustc_interface::Config) { - config.override_queries = Some(override_queries); - } - - fn after_parsing<'tcx>( - &mut self, - _compiler: &Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - let parse = queries.parse().unwrap(); - let mut parse = parse.peek_mut(); - parse.items.push(P(Item { - attrs: Vec::new(), - id: NodeId::from_u32(0), - span: DUMMY_SP, - vis: Visibility { - kind: VisibilityKind::Inherited, - span: DUMMY_SP, - tokens: None, - }, - ident: Ident::from_str("c2rust_analysis_rt"), - kind: ItemKind::ExternCrate(None), - tokens: None, - })); - Compilation::Continue - } -} - -fn override_queries( - _sess: &Session, - providers: &mut Providers, - _extern_providers: &mut ExternProviders, -) { - providers.mir_built = |tcx, def: WithOptConstParam| { - let mut providers = Providers::default(); - rustc_mir_build::provide(&mut providers); - - let steal_mir = (providers.mir_built)(tcx, def); - let mut mir = steal_mir.steal(); - - let body_did = def.did.to_def_id(); - let fn_ty = tcx.type_of(body_did); - if fn_ty.is_fn() && !tcx.is_const_fn(body_did) && !tcx.is_static(body_did) { - INSTRUMENTER.instrument_fn(tcx, &mut mir, body_did); - - Validator { - when: "After dynamic instrumentation".to_string(), - mir_phase: mir.phase, - } - .run_pass(tcx, &mut mir); - } - - tcx.alloc_steal_mir(mir) - }; -}