use std::path::{Path, PathBuf};
use std::time::Duration;
use time::OffsetDateTime;
use crate::hooks::*;
#[derive(Clone)]
pub struct Config<LD, GD> {
pub(crate) as_size: usize,
pub(crate) nb_workers: u32,
pub(crate) working_directory: Option<PathBuf>,
pub(crate) corpus_directory: Option<PathBuf>,
pub(crate) timeout: Duration,
pub(crate) iterations: Option<u64>,
pub(crate) seed: u64,
pub(crate) coverage: bool,
pub(crate) tracer: bool,
pub(crate) tracer_hook: Option<HookFn<LD, GD>>,
pub(crate) save_crashes: bool,
pub(crate) save_timeouts: bool,
pub(crate) load_corpus_at_init: bool,
pub(crate) max_testcase_size: usize,
pub(crate) max_nb_mutations: usize,
pub(crate) crash_verif_iterations: usize,
pub(crate) remove_coverage_hooks_on_hit: bool,
pub(crate) comparison_unrolling: bool,
}
enum ConfigType {
Executor,
Fuzzer,
}
pub enum ConfigData<LD, GD> {
Executor(Config<LD, GD>),
Fuzzer(Config<LD, GD>),
}
#[derive(Clone)]
pub struct FuzzConfig<LD, GD> {
phantom_ld: std::marker::PhantomData<LD>,
phantom_gd: std::marker::PhantomData<GD>,
}
impl<LD, GD> FuzzConfig<LD, GD> {
pub fn builder(
as_size: usize,
working_dir: impl AsRef<Path>,
corpus_dir: impl AsRef<Path>,
) -> ConfigBuilder<LD, GD> {
ConfigBuilder::<LD, GD>::new(
as_size,
Some(working_dir),
Some(corpus_dir),
ConfigType::Fuzzer,
)
}
}
#[derive(Clone)]
pub struct ExecConfig<LD, GD> {
phantom_ld: std::marker::PhantomData<LD>,
phantom_gd: std::marker::PhantomData<GD>,
}
impl<LD, GD> ExecConfig<LD, GD> {
pub fn builder(as_size: usize) -> ConfigBuilder<LD, GD> {
ConfigBuilder::<LD, GD>::new(
as_size,
None::<&std::path::Path>,
None::<&std::path::Path>,
ConfigType::Executor,
)
}
}
pub struct ConfigBuilder<LD, GD> {
config_type: ConfigType,
config: Config<LD, GD>,
}
impl<LD, GD> ConfigBuilder<LD, GD> {
fn new(
as_size: usize,
working_dir: Option<impl AsRef<Path>>,
corpus_dir: Option<impl AsRef<Path>>,
config_type: ConfigType,
) -> Self {
Self {
config_type,
config: Config {
as_size,
nb_workers: 1,
working_directory: working_dir.map(|d| d.as_ref().to_owned()),
corpus_directory: corpus_dir.map(|d| d.as_ref().to_owned()),
timeout: Duration::new(3, 0),
iterations: None,
seed: OffsetDateTime::now_utc().nanosecond() as u64,
coverage: true,
tracer: false,
tracer_hook: None,
save_crashes: true,
save_timeouts: true,
load_corpus_at_init: true,
max_testcase_size: 0x1000,
max_nb_mutations: 10,
crash_verif_iterations: 3,
remove_coverage_hooks_on_hit: true,
comparison_unrolling: false,
},
}
}
pub fn build(self) -> ConfigData<LD, GD> {
match self.config_type {
ConfigType::Fuzzer => ConfigData::Fuzzer(self.config),
ConfigType::Executor => ConfigData::Executor(self.config),
}
}
pub fn as_size(mut self, as_size: usize) -> Self {
self.config.as_size = as_size;
self
}
pub fn nb_workers(mut self, nb_workers: u32) -> Self {
self.config.nb_workers = nb_workers;
self
}
pub fn working_directory(mut self, working_directory: impl AsRef<Path>) -> Self {
self.config.working_directory = Some(working_directory.as_ref().to_owned());
self
}
pub fn corpus_directory(mut self, corpus_directory: impl AsRef<Path>) -> Self {
self.config.corpus_directory = Some(corpus_directory.as_ref().to_owned());
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.config.timeout = timeout;
self
}
pub fn iterations(mut self, iterations: Option<u64>) -> Self {
self.config.iterations = iterations;
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.config.seed = seed;
self
}
pub fn coverage(mut self, coverage: bool) -> Self {
self.config.coverage = coverage;
self
}
pub fn tracer(mut self, tracer: bool) -> Self {
self.config.tracer = tracer;
self
}
pub fn tracer_hook(mut self, tracer_hook: HookFn<LD, GD>) -> Self {
self.config.tracer_hook = Some(tracer_hook);
self
}
pub fn save_crashes(mut self, save_crashes: bool) -> Self {
self.config.save_crashes = save_crashes;
self
}
pub fn save_timeouts(mut self, save_timeouts: bool) -> Self {
self.config.save_timeouts = save_timeouts;
self
}
pub fn load_corpus_at_init(mut self, load_corpus_at_init: bool) -> Self {
self.config.load_corpus_at_init = load_corpus_at_init;
self
}
pub fn max_testcase_size(mut self, max_testcase_size: usize) -> Self {
self.config.max_testcase_size = max_testcase_size;
self
}
pub fn max_nb_mutations(mut self, max_nb_mutations: usize) -> Self {
self.config.max_nb_mutations = max_nb_mutations;
self
}
pub fn crash_verif_iterations(mut self, crash_verif_iterations: usize) -> Self {
self.config.crash_verif_iterations = 1 + crash_verif_iterations;
self
}
pub fn remove_coverage_hooks_on_hit(mut self, remove_coverage_hooks_on_hit: bool) -> Self {
self.config.remove_coverage_hooks_on_hit = remove_coverage_hooks_on_hit;
self
}
pub fn comparison_unrolling(mut self, comparison_unrolling: bool) -> Self {
self.config.comparison_unrolling = comparison_unrolling;
self
}
}