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
2 changes: 2 additions & 0 deletions docs/docs/tooling/fuzzing.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ Additional fuzzing-specific options include:
Only run harnesses that match exactly
--timeout <TIMEOUT>
Maximum time in seconds to spend fuzzing per harness (default: no timeout)
--max-executions <MAX_EXECUTIONS>
Maximum number of executions of ACIR and Brillig per harness (default: no limit)

`--show-output` and `--oracle-resolver` can be used in the same way as with regular execution and testing.
It is recommended to use `--skip-underconstrained-check` to increase compilation speed.
Expand Down
12 changes: 12 additions & 0 deletions tooling/greybox_fuzzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@

use noirc_artifacts::program::ProgramArtifact;
use rand::prelude::*;
use rand::{Rng, SeedableRng};

Check warning on line 43 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Seedable)
use rand_xorshift::XorShiftRng;

Check warning on line 44 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (xorshift)

use rayon::prelude::IntoParallelIterator;
use std::io::Write;
Expand All @@ -49,14 +49,14 @@

const FOREIGN_CALL_FAILURE_SUBSTRING: &str = "Failed calling external resolver.";

/// We aim the number of testcases per round so one round takes these many microseconds

Check warning on line 52 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (testcases)
const SINGLE_FUZZING_ROUND_TARGET_TIME: u128 = 100_000u128;

/// Minimum pulse interval in milliseconds for printing metrics
const MINIMUM_PULSE_INTERVAL_MILLIS: u64 = 1000u64;

/// A seed for the XorShift RNG for use during mutation
type SimpleXorShiftRNGSeed = <XorShiftRng as SeedableRng>::Seed;

Check warning on line 59 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Seedable)

/// Information collected from testcase execution on success
pub type WitnessAndCoverage = (WitnessStack<FieldElement>, Option<Vec<u32>>);
Expand All @@ -73,7 +73,7 @@
main_testcase_id: TestCaseId,
/// An optional id of a second testcase that will be used for splicing
additional_testcase_id: Option<TestCaseId>,
/// A seed for the PRNG that will be used for mutating/splicing

Check warning on line 76 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (PRNG)
seed: SimpleXorShiftRNGSeed,
}

Expand All @@ -88,7 +88,7 @@
}

/// Create a task for executing a testcase without mutation
pub fn mutationless(main_testcase_id: TestCaseId) -> Self {

Check warning on line 91 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mutationless)
Self {
main_testcase_id,
additional_testcase_id: None,
Expand All @@ -96,7 +96,7 @@
}
}

pub fn prng_seed(&self) -> SimpleXorShiftRNGSeed {

Check warning on line 99 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (prng)
self.seed
}
pub fn main_id(&self) -> TestCaseId {
Expand All @@ -107,7 +107,7 @@
}
}

/// Contains information from parallel execution of testcases for quick single-threaded processing

Check warning on line 110 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (testcases)
/// If no new coverage is detected, the fuzzer can simply quickly update the timing metrics without parsing the outcome
#[derive(Debug)]
struct FastParallelFuzzResult {
Expand Down Expand Up @@ -179,9 +179,9 @@
total_acir_execution_time: u128,
/// Total time spent executing Brillig programs in microseconds
total_brillig_execution_time: u128,
/// Total time spent mutating testcases

Check warning on line 182 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (testcases)
total_mutation_time: u128,
/// The number of unique testcases run

Check warning on line 184 in tooling/greybox_fuzzer/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (testcases)
processed_testcase_count: usize,
/// Number of testcases removed from the corpus
removed_testcase_count: usize,
Expand Down Expand Up @@ -278,6 +278,8 @@
pub timeout: u64,
/// Whether to output progress to stdout or not.
pub show_progress: bool,
/// Maximum number of executions of ACIR and Brillig (default: no limit)
pub max_executions: usize,
}

pub enum FuzzedExecutorFailureConfiguration {
Expand Down Expand Up @@ -348,6 +350,9 @@

/// Maximum time in seconds to spend fuzzing (default: no timeout)
timeout: u64,

/// Maximum number of executions of ACIR and Brillig (default: no limit)
max_executions: usize,
}
pub struct AcirAndBrilligPrograms {
pub acir_program: ProgramArtifact,
Expand Down Expand Up @@ -412,6 +417,7 @@
),
timeout: fuzz_execution_config.timeout,
metrics: Metrics::default(),
max_executions: fuzz_execution_config.max_executions,
}
}

Expand Down Expand Up @@ -969,6 +975,12 @@
if self.timeout > 0 && time_tracker.elapsed() >= Duration::from_secs(self.timeout) {
return FuzzTestResult::Success;
}
// Check if we've exceeded the maximum number of executions
if self.max_executions > 0
&& self.metrics.processed_testcase_count >= self.max_executions
{
return FuzzTestResult::Success;
}
}

if self.minimize_corpus {
Expand Down
3 changes: 3 additions & 0 deletions tooling/nargo/src/ops/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub struct FuzzExecutionConfig {
pub timeout: u64,
/// Whether to output progress to stdout or not.
pub show_progress: bool,
/// Maximum number of executions of ACIR and Brillig (default: no limit)
pub max_executions: usize,
}

/// Folder configuration for fuzzing
Expand Down Expand Up @@ -208,6 +210,7 @@ where
num_threads: fuzz_execution_config.num_threads,
timeout: fuzz_execution_config.timeout,
show_progress: fuzz_execution_config.show_progress,
max_executions: fuzz_execution_config.max_executions,
},
failure_configuration,
FuzzedExecutorFolderConfiguration {
Expand Down
11 changes: 8 additions & 3 deletions tooling/nargo_cli/src/cli/fuzz_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ pub(crate) struct FuzzCommand {
oracle_resolver: Option<String>,

/// Maximum time in seconds to spend fuzzing (default: no timeout)
#[arg(long)]
timeout: Option<u64>,
#[arg(long, default_value = "0")]
timeout: u64,

/// Maximum number of executions of ACIR and Brillig per harness (default: no limit)
#[arg(long, default_value = "0")]
max_executions: usize,
}
impl WorkspaceCommand for FuzzCommand {
fn package_selection(&self) -> PackageSelection {
Expand Down Expand Up @@ -153,9 +157,10 @@ pub(crate) fn run(args: FuzzCommand, workspace: Workspace) -> Result<(), CliErro
fuzzing_failure_dir: args.fuzzing_failure_dir,
};
let fuzz_execution_config = FuzzExecutionConfig {
timeout: args.timeout.unwrap_or(0),
timeout: args.timeout,
num_threads: args.num_threads,
show_progress: true,
max_executions: args.max_executions,
};

let fuzzing_reports: Vec<Vec<(String, FuzzingRunStatus)>> = workspace
Expand Down
1 change: 1 addition & 0 deletions tooling/nargo_cli/src/cli/test_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ impl<'a> TestRunner<'a> {
num_threads: 1,
timeout: self.args.fuzz_timeout,
show_progress: false,
max_executions: 0,
},
};

Expand Down
Loading