Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/bin/cargo-ziggy/add_seeds.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::*;
use anyhow::bail;
use crate::{AddSeeds, Common};
use anyhow::{Context, bail};
use std::{env, process};

impl AddSeeds {
pub fn add_seeds(&self) -> Result<(), anyhow::Error> {
pub fn add_seeds(&self, common: &Common) -> Result<(), anyhow::Error> {
eprintln!("Adding seeds to AFL");

let req = semver::VersionReq::parse(">=0.14.5").unwrap();
Expand All @@ -27,11 +27,11 @@ impl AddSeeds {
);
}

let target = find_target(&self.target)?;
let target = common.resolve_bin(self.target.clone())?;
let input = self.input.display().to_string();

let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
process::Command::new(&cargo)
common
.cargo()
.args([
"afl",
"addseeds",
Expand Down
33 changes: 21 additions & 12 deletions src/bin/cargo-ziggy/build.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
use crate::Build;
use anyhow::{Context, Result, bail};
use crate::{Build, Common, util::Context};
use anyhow::{Context as _, Result, bail};
use console::style;
use std::{env, process};

impl Build {
/// Build the fuzzers
pub fn build(&self) -> Result<(), anyhow::Error> {
pub fn build(&self, common: &Common) -> Result<(), anyhow::Error> {
// No fuzzers for you
if self.no_afl && self.no_honggfuzz {
bail!("Pick at least one fuzzer");
}

// The cargo executable
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
let cx = Context::new(common, self.target.clone())?;

if !self.no_afl {
eprintln!(" {} afl", style("Building").red().bold());
let target_dir = format!("--target-dir={}", super::target_dir().join("afl"));
let mut afl_args = vec!["afl", "build", "--features=ziggy/afl", &target_dir];
let target_dir = format!("--target-dir={}", cx.target_dir.join("afl"));
let mut afl_args = vec![
"afl",
"build",
"--features=ziggy/afl",
&target_dir,
"--bin",
&cx.bin_target,
];

// Add the --release argument if self.release is true
if self.release {
Expand All @@ -29,7 +35,8 @@ impl Build {
let mut rust_doc_flags = env::var("RUSTDOCFLAGS").unwrap_or_default();

// First fuzzer we build: AFL++
let run = process::Command::new(&cargo)
let run = common
.cargo()
.args(&afl_args)
.env("AFL_QUIET", "1")
.env("AFL_LLVM_CMPLOG", "1") // for afl.rs feature "plugins"
Expand Down Expand Up @@ -57,7 +64,8 @@ impl Build {
rust_flags.push_str("-Copt-level=0");
rust_doc_flags.push_str(" -Zsanitizer=address ");

let run = process::Command::new(&cargo)
let run = common
.cargo()
.args(afl_args)
.env("AFL_QUIET", "1")
// need to specify for afl.rs so that we build with -Copt-level=0
Expand Down Expand Up @@ -85,9 +93,10 @@ impl Build {
eprintln!(" {} honggfuzz", style("Building").red().bold());

// Second fuzzer we build: Honggfuzz
let run = process::Command::new(&cargo)
.args(["hfuzz", "build"])
.env("CARGO_TARGET_DIR", super::target_dir().join("honggfuzz"))
let run = common
.cargo()
.args(["hfuzz", "build", "--bin", &cx.bin_target])
.env("CARGO_TARGET_DIR", cx.target_dir.join("honggfuzz"))
.env("HFUZZ_BUILD_ARGS", "--features=ziggy/honggfuzz")
.env("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or_default())
.stdout(process::Stdio::piped())
Expand Down
15 changes: 8 additions & 7 deletions src/bin/cargo-ziggy/clean.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
use crate::Clean;
use crate::{Clean, Common};
use anyhow::{Error, bail};
use std::{env, process::Command};

impl Clean {
pub fn clean(&self) -> Result<(), Error> {
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));

pub fn clean(&self, common: &Common) -> Result<(), Error> {
let Ok(target_dir) = common.target_dir() else {
return Ok(());
};
let clean = |target, target_triple: Option<&str>, try_release| -> Result<(), Error> {
let already_profile = self
.args
.iter()
.any(|arg| arg.as_encoded_bytes().starts_with(b"--profile") || arg == "--release");
let status = Command::new(&cargo)
let status = common
.cargo()
.arg("clean")
.arg("-q")
.args(&self.args)
.args(target_triple.map(|triple| format!("--target={triple}")))
.args((!already_profile && try_release).then_some("--release"))
.env("CARGO_TARGET_DIR", super::target_dir().join(target))
.env("CARGO_TARGET_DIR", target_dir.join(target))
.status()
.expect("Error running cargo clean command");
if !status.success() {
Expand Down
55 changes: 27 additions & 28 deletions src/bin/cargo-ziggy/coverage.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{Cover, find_target};
use anyhow::{Context, Result, anyhow, bail};
use cargo_metadata::camino::Utf8PathBuf;
use crate::{Common, Cover, util::Context, util::Utf8PathBuf};
use anyhow::{Context as _, Result, anyhow, bail};
use glob::glob;
use indicatif::{ProgressBar, ProgressStyle};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
Expand All @@ -16,7 +15,8 @@ thread_local! {
}

impl Cover {
pub fn generate_coverage(&mut self) -> Result<(), anyhow::Error> {
pub fn generate_coverage(&self, common: &Common) -> Result<(), anyhow::Error> {
let cx = Context::new(common, self.target.clone())?;
process::Command::new("grcov")
.arg("--version")
.output()
Expand All @@ -40,29 +40,26 @@ impl Cover {

eprintln!("Generating coverage");

self.target =
find_target(&self.target).context("⚠️ couldn't find the target to start coverage")?;

if let Some(path) = &self.source
&& !path.try_exists()?
{
bail!("Source directory specified, but path does not exist!");
}

// build the runner
Self::build_runner()?;
Self::build_runner(common)?;

if !self.keep {
// We remove the previous coverage files
Self::clean_old_cov()?;
Self::clean_old_cov(&cx)?;
}

let input_path = PathBuf::from(
self.input
.display()
.to_string()
.replace("{ziggy_output}", &self.ziggy_output.display().to_string())
.replace("{target_name}", &self.target),
.replace("{target_name}", &cx.bin_target),
);

let coverage_corpus = if input_path.is_dir() {
Expand All @@ -87,16 +84,16 @@ impl Cover {
.display()
.to_string()
.replace("{ziggy_output}", &self.ziggy_output.display().to_string())
.replace("{target_name}", &self.target);
.replace("{target_name}", &cx.bin_target);

delete_dir_or_file(&coverage_dir)?;

// Get the absolute path for the coverage directory to ensure .profraw files
// are created in the correct location, even in workspace scenarios
let base_dir = super::target_dir().join("coverage/debug");
let base_dir = cx.target_dir.join("coverage/debug");
let coverage_target_dir = base_dir.join("deps");
let cfg = Cfg::new(
base_dir.join(&self.target),
base_dir.join(&cx.bin_target),
coverage_target_dir.join("coverage-%p-%m.profraw"),
);

Expand All @@ -109,7 +106,7 @@ impl Cover {
.unwrap()
.progress_chars("#>-"),
);
let log_dir = self.ziggy_output.join(format!("{}/logs", &self.target));
let log_dir = self.ziggy_output.join(format!("{}/logs", &cx.bin_target));
fs::create_dir_all(&log_dir)?;
let log_file = std::sync::Mutex::new(std::fs::File::create(log_dir.join("coverage.log"))?);
coverage_corpus.into_par_iter().for_each(|file| {
Expand Down Expand Up @@ -137,7 +134,7 @@ impl Cover {
// We generate the code coverage report
eprintln!("\n Generating coverage report");
Self::run_grcov(
&self.target,
&cx,
output_types,
&coverage_dir,
&source_or_workspace_root,
Expand All @@ -146,22 +143,25 @@ impl Cover {
}

/// Build the runner with the appropriate flags for coverage
pub fn build_runner() -> Result<(), anyhow::Error> {
// The cargo executable
let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
pub fn build_runner(common: &Common) -> Result<(), anyhow::Error> {
let target_dir = common.target_dir()?;

let mut coverage_rustflags =
env::var("COVERAGE_RUSTFLAGS").unwrap_or_else(|_| "-Cinstrument-coverage".to_string());
coverage_rustflags.push(' ');
coverage_rustflags.push_str(&env::var("RUSTFLAGS").unwrap_or_default());
let target_dir = format!("--target-dir={}", super::target_dir().join("coverage"));

let build = process::Command::new(&cargo)
.args(["rustc", "--features=ziggy/coverage", &target_dir])
let build = common
.cargo()
.args([
"rustc",
"--features=ziggy/coverage",
&format!("--target-dir={}", target_dir.join("coverage")),
])
.env("RUSTFLAGS", coverage_rustflags)
.env(
"LLVM_PROFILE_FILE",
super::target_dir().join("coverage/debug/deps/build-%p-%m.profraw"),
target_dir.join("coverage/debug/deps/build-%p-%m.profraw"),
)
.spawn()
.context("⚠️ couldn't spawn rustc for coverage")?
Expand All @@ -174,16 +174,16 @@ impl Cover {
}

pub fn run_grcov(
target: &str,
cx: &Context,
output_types: &str,
coverage_dir: &str,
source_or_workspace_root: &str,
threads: Option<usize>,
) -> Result<(), anyhow::Error> {
let coverage = process::Command::new("grcov")
.args([
crate::target_dir().join("coverage/debug/deps").as_str(),
&format!("-b={}/coverage/debug/{target}", super::target_dir()),
cx.target_dir.join("coverage/debug/deps").as_str(),
&format!("-b={}/coverage/debug/{}", cx.target_dir, cx.bin_target),
&format!("-s={source_or_workspace_root}"),
&format!("-t={output_types}"),
"--llvm",
Expand All @@ -202,10 +202,9 @@ impl Cover {
Ok(())
}

pub fn clean_old_cov() -> Result<(), anyhow::Error> {
pub fn clean_old_cov(cx: &Context) -> Result<(), anyhow::Error> {
// Use absolute path to ensure we clean the correct location in workspaces
let coverage_deps_dir = super::target_dir().join("coverage/debug/deps");
let pattern = coverage_deps_dir.join("*.profraw");
let pattern = cx.target_dir.join("*.profraw");

if let Ok(profile_files) = glob(pattern.as_str()) {
for file in profile_files.flatten() {
Expand Down
Loading