diff --git a/Cargo.lock b/Cargo.lock index 8895065d1..67d29791e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "afl" version = "0.15.9" @@ -71,6 +86,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +dependencies = [ + "backtrace", +] + [[package]] name = "arbitrary" version = "1.3.2" @@ -101,6 +125,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -122,6 +161,7 @@ dependencies = [ name = "cargo-afl" version = "0.15.9" dependencies = [ + "anyhow", "assert_cmd", "clap", "ctor", @@ -133,6 +173,12 @@ dependencies = [ "xdg", ] +[[package]] +name = "cc" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907d8581360765417f8f2e0e7d602733bbed60156b4465b7617243689ef9b83d" + [[package]] name = "cfg-if" version = "1.0.0" @@ -249,6 +295,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "heck" version = "0.5.0" @@ -288,6 +340,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -303,6 +364,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + [[package]] name = "predicates" version = "3.1.0" @@ -380,6 +450,12 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc_version" version = "0.4.0" diff --git a/cargo-afl/Cargo.toml b/cargo-afl/Cargo.toml index e1b593a09..2d71c1157 100644 --- a/cargo-afl/Cargo.toml +++ b/cargo-afl/Cargo.toml @@ -14,6 +14,7 @@ homepage = "https://github.com/rust-fuzz/afl.rs" edition = "2021" [build-dependencies] +anyhow = { version = "1.0", features = ["backtrace"] } clap = { version = "4.5", features = ["cargo", "derive"] } fs_extra = "1.3" home = "0.5" @@ -22,6 +23,7 @@ tempfile = "3.10" xdg = "2.5" [dependencies] +anyhow = { version = "1.0", features = ["backtrace"] } clap = { version = "4.5", features = ["cargo", "derive", "string"] } fs_extra = "1.3" home = "0.5" diff --git a/cargo-afl/src/common.rs b/cargo-afl/src/common.rs index 1590e879a..c4ef2b06b 100644 --- a/cargo-afl/src/common.rs +++ b/cargo-afl/src/common.rs @@ -1,8 +1,8 @@ #![deny(clippy::disallowed_macros, clippy::expect_used, clippy::unwrap_used)] +use anyhow::{Context, Result}; use std::env; use std::ffi::OsStr; -use std::io::{Error, Result}; use std::path::{Path, PathBuf}; fn xdg_dir() -> Result { @@ -10,7 +10,7 @@ fn xdg_dir() -> Result { let prefix = Path::new("afl.rs") .join(afl_rustc_version) .join(pkg_version()); - xdg::BaseDirectories::with_prefix(prefix).map_err(Error::other) + xdg::BaseDirectories::with_prefix(prefix).map_err(Into::into) } fn data_dir(dir_name: &str) -> Result { @@ -23,13 +23,13 @@ fn data_dir(dir_name: &str) -> Result { // don't change that for now for normal builds. // smoelius: AFL++ is no longer built on docs.rs. let xdg_dir = xdg_dir()?; - xdg_dir.create_data_directory(dir_name) + xdg_dir.create_data_directory(dir_name).map_err(Into::into) } const SHORT_COMMIT_HASH_LEN: usize = 7; pub fn afl_rustc_version() -> Result { - let version_meta = rustc_version::version_meta().map_err(Error::other)?; + let version_meta = rustc_version::version_meta()?; let mut ret = String::from("rustc-"); ret.push_str(&version_meta.semver.to_string()); if let Some(commit_hash) = version_meta.commit_hash { @@ -73,8 +73,12 @@ pub fn archive_file_path() -> Result { #[allow(dead_code)] pub fn plugins_available() -> Result { let afl_llvm_dir = afl_llvm_dir()?; - for result in afl_llvm_dir.read_dir()? { - let entry = result?; + for result in afl_llvm_dir + .read_dir() + .with_context(|| format!("could not read {afl_llvm_dir:?}"))? + { + let entry = + result.with_context(|| format!("could not read `DirEntry` in {afl_llvm_dir:?}"))?; let file_name = entry.file_name(); if Path::new(&file_name).extension() == Some(OsStr::new("so")) { return Ok(true); diff --git a/cargo-afl/src/config.rs b/cargo-afl/src/config.rs index 8c4370fad..4bbba579a 100644 --- a/cargo-afl/src/config.rs +++ b/cargo-afl/src/config.rs @@ -1,8 +1,8 @@ #![deny(clippy::disallowed_macros, clippy::expect_used, clippy::unwrap_used)] +use anyhow::{anyhow, Context, Result}; use clap::Parser; use std::ffi::OsStr; -use std::io::{Error, Result}; use std::path::Path; use std::process::{Command, ExitStatus, Stdio}; @@ -40,16 +40,16 @@ pub fn config(args: &Args) -> Result<()> { let archive_file_path = common::archive_file_path()?; if !args.force && archive_file_path.exists() && args.plugins == common::plugins_available()? { let version = common::afl_rustc_version()?; - return Err(Error::other(format!( + return Err(anyhow!( "AFL LLVM runtime was already built for Rust {version}; run `cargo afl config --build \ --force` to rebuild it." - ))); + )); } let afl_src_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join(AFL_SRC_PATH); let afl_src_dir_str = &afl_src_dir.to_string_lossy(); - let tempdir = tempfile::tempdir()?; + let tempdir = tempfile::tempdir().with_context(|| "could not create temporary directory")?; if afl_src_dir.join(".git").is_dir() { let success = Command::new("git") @@ -58,7 +58,7 @@ pub fn config(args: &Args) -> Result<()> { .as_ref() .map_or(false, ExitStatus::success); if !success { - return Err(Error::other("could not run 'git'")); + return Err(anyhow!("could not run 'git'")); } } else { let _: u64 = fs_extra::dir::copy( @@ -68,8 +68,7 @@ pub fn config(args: &Args) -> Result<()> { content_only: true, ..Default::default() }, - ) - .map_err(Error::other)?; + )?; } let work_dir = tempdir.path(); @@ -83,7 +82,7 @@ pub fn config(args: &Args) -> Result<()> { let afl_dir = common::afl_dir()?; let Some(dir) = afl_dir.parent().map(Path::to_path_buf) else { - return Err(Error::other("could not get afl dir parent")); + return Err(anyhow!("could not get afl dir parent")); }; eprintln!("Artifacts written to {}", dir.display()); @@ -121,7 +120,7 @@ fn build_afl(args: &Args, work_dir: &Path) -> Result<()> { let success = command.status().as_ref().map_or(false, ExitStatus::success); if !success { - return Err(Error::other("could not run 'make install'")); + return Err(anyhow!("could not run 'make install'")); } Ok(()) @@ -130,7 +129,7 @@ fn build_afl(args: &Args, work_dir: &Path) -> Result<()> { fn build_afl_llvm_runtime(args: &Args, work_dir: &Path) -> Result<()> { let object_file_path = common::object_file_path()?; let _: u64 = std::fs::copy(work_dir.join("afl-compiler-rt.o"), &object_file_path) - .map_err(|error| Error::other(format!("could not copy object file: {error}")))?; + .with_context(|| "could not copy object file")?; let archive_file_path = common::archive_file_path()?; let mut command = Command::new(AR_CMD); @@ -146,7 +145,7 @@ fn build_afl_llvm_runtime(args: &Args, work_dir: &Path) -> Result<()> { let success = command.status().as_ref().map_or(false, ExitStatus::success); if !success { - return Err(Error::other("could not run 'ar'")); + return Err(anyhow!("could not run 'ar'")); } Ok(()) @@ -154,8 +153,11 @@ fn build_afl_llvm_runtime(args: &Args, work_dir: &Path) -> Result<()> { fn copy_afl_llvm_plugins(_args: &Args, work_dir: &Path) -> Result<()> { // Iterate over the files in the directory. - for result in work_dir.read_dir()? { - let entry = result?; + for result in work_dir + .read_dir() + .with_context(|| format!("could not read {work_dir:?}"))? + { + let entry = result.with_context(|| format!("could not read `DirEntry` in {work_dir:?}"))?; let file_name = entry.file_name(); // Get the file extension. Only copy the files that are shared objects. @@ -163,11 +165,7 @@ fn copy_afl_llvm_plugins(_args: &Args, work_dir: &Path) -> Result<()> { // Attempt to copy the shared object file. let afl_llvm_dir = common::afl_llvm_dir()?; let _: u64 = std::fs::copy(work_dir.join(&file_name), afl_llvm_dir.join(&file_name)) - .map_err(|error| { - Error::other(format!( - "could not copy shared object file {file_name:?}: {error}" - )) - })?; + .with_context(|| format!("could not copy shared object file {file_name:?}"))?; } } @@ -176,9 +174,9 @@ fn copy_afl_llvm_plugins(_args: &Args, work_dir: &Path) -> Result<()> { fn check_llvm_and_get_config() -> Result { // Make sure we are on nightly for the -Z flags - let version_meta = rustc_version::version_meta().map_err(Error::other)?; + let version_meta = rustc_version::version_meta()?; if version_meta.channel != rustc_version::Channel::Nightly { - return Err(Error::other( + return Err(anyhow!( "cargo-afl must be compiled with nightly for the plugins feature", )); } @@ -186,7 +184,7 @@ fn check_llvm_and_get_config() -> Result { .llvm_version .map(|llvm_version| llvm_version.major.to_string()) else { - return Err(Error::other("could not get llvm version")); + return Err(anyhow!("could not get llvm version")); }; // Fetch the llvm version of the rust toolchain and set the LLVM_CONFIG environment variable to the same version @@ -200,33 +198,22 @@ fn check_llvm_and_get_config() -> Result { // check if llvm tools are installed and with the good version for the plugin compilation let mut command = Command::new(&llvm_config); command.args(["--version"]); - let out = match command.output() { - Ok(out) => out, - Err(error) => { - return Err(Error::other(format!( - "could not run {llvm_config} --version: {error}" - ))); - } - }; + let out = command + .output() + .with_context(|| format!("could not run {llvm_config} --version"))?; - let version = match String::from_utf8(out.stdout) { - Ok(version) => version, - Err(error) => { - return Err(Error::other(format!( - "could not convert {llvm_config} --version output to utf8: {error}" - ))); - } - }; + let version = String::from_utf8(out.stdout) + .with_context(|| format!("could not convert {llvm_config} --version output to utf8"))?; let Some(major) = version.split('.').next() else { - return Err(Error::other(format!( + return Err(anyhow!( "could not get major from {llvm_config} --version output", - ))); + )); }; if major != llvm_version { - return Err(Error::other(format!( + return Err(anyhow!( "{llvm_config} --version output does not contain expected major version \ ({llvm_version})", - ))); + )); } Ok(llvm_config)