diff --git a/src/options.rs b/src/options.rs index 8c404f8..7eb65a4 100644 --- a/src/options.rs +++ b/src/options.rs @@ -14,8 +14,9 @@ pub use self::{ list::List, run::Run, tmin::Tmin, }; +use anyhow::{bail, Error, Result}; use clap::{Parser, ValueEnum}; -use std::{fmt as stdfmt, path::PathBuf}; +use std::{fmt as stdfmt, path::PathBuf, str::FromStr}; #[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)] pub enum Sanitizer { @@ -279,6 +280,24 @@ impl stdfmt::Display for FuzzDirWrapper { } } +#[derive(Clone, Debug)] +pub enum FuzzEngine { + LibFuzzer, + LibAfl, +} + +impl FromStr for FuzzEngine { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "libfuzzer" => Ok(Self::LibFuzzer), + "libafl" => Ok(Self::LibAfl), + _ => bail!("invalid fuzz engine: '{s}'. Must be one of: 'libfuzzer', 'libafl'"), + } + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/options/init.rs b/src/options/init.rs index ae86c6b..589aa8a 100644 --- a/src/options/init.rs +++ b/src/options/init.rs @@ -1,4 +1,8 @@ -use crate::{options::FuzzDirWrapper, project::FuzzProject, RunCommand}; +use crate::{ + options::{FuzzDirWrapper, FuzzEngine}, + project::FuzzProject, + RunCommand, +}; use anyhow::Result; use clap::Parser; @@ -12,9 +16,11 @@ pub struct Init { /// Whether to create a separate workspace for fuzz targets crate pub fuzzing_workspace: Option, - #[arg(long, value_parser = clap::builder::BoolishValueParser::new(), default_value = "false")] - /// Whether to use libafl's libfuzzer_sys-compatible API for improved fuzzing performance - pub use_libafl: Option, + #[arg(long, default_value = "libfuzzer")] + /// The fuzz engine that the project should use. + /// + /// Options: libfuzzer, libafl + pub fuzz_engine: FuzzEngine, #[command(flatten)] pub fuzz_dir_wrapper: FuzzDirWrapper, diff --git a/src/project.rs b/src/project.rs index 6b53823..c75e55b 100644 --- a/src/project.rs +++ b/src/project.rs @@ -70,7 +70,7 @@ impl FuzzProject { .write_fmt(toml_template!( manifest.crate_name, manifest.edition, - init.use_libafl, + init.fuzz_engine, init.fuzzing_workspace )) .with_context(|| format!("failed to write to {}", cargo_toml.display()))?; diff --git a/src/templates.rs b/src/templates.rs index 0f1b6e9..a8c0f3f 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -1,5 +1,5 @@ macro_rules! toml_template { - ($name:expr, $edition:expr, $use_libafl:expr, $fuzzing_workspace:expr) => { + ($name:expr, $edition:expr, $fuzz_engine:expr, $fuzzing_workspace:expr) => { format_args!( r##"[package] name = "{name}-fuzz" @@ -21,10 +21,11 @@ path = ".." } else { String::new() }, - libfuzzer_sys_dep = if let Some(true) = $use_libafl { - r##"libfuzzer-sys = { version = "0.15.3", package = "libafl_libfuzzer" }"## - } else { - r##"libfuzzer-sys = "0.4""## + libfuzzer_sys_dep = match $fuzz_engine { + crate::options::FuzzEngine::LibFuzzer => r#"libfuzzer-sys = "0.4""#, + crate::options::FuzzEngine::LibAfl => { + r#"libfuzzer-sys = { version = "0.15.3", package = "libafl_libfuzzer" }"# + } }, workspace = if let Some(true) = $fuzzing_workspace { r##" diff --git a/tests/tests/main.rs b/tests/tests/main.rs index e501183..3b94bb3 100644 --- a/tests/tests/main.rs +++ b/tests/tests/main.rs @@ -159,7 +159,21 @@ fn init_defines_correct_dependency() { let expected_dependency_attrs = &format!("[dependencies.{name}]\npath = \"..\"", name = project_name); assert!(cargo_toml.contains(expected_dependency_attrs)); - assert!(cargo_toml.contains(r#"libfuzzer-sys = "0.4""#)) + assert!(cargo_toml.contains(r#"libfuzzer-sys = "0.4""#)); +} + +#[test] +fn init_with_libfuzzer() { + let project = project("init_with_libfuzzer").build(); + project + .cargo_fuzz() + .arg("init") + .arg("--fuzz-engine=libfuzzer") + .assert() + .success(); + + let cargo_toml = fs::read_to_string(project.fuzz_cargo_toml()).unwrap(); + assert!(cargo_toml.contains(r#"libfuzzer-sys = "0.4""#)); } #[test] @@ -168,7 +182,7 @@ fn init_with_libafl() { project .cargo_fuzz() .arg("init") - .arg("--use-libafl=true") + .arg("--fuzz-engine=libafl") .assert() .success();