Skip to main content

ziggy/
lib.rs

1#![doc = include_str!("../README.md")]
2#[cfg(feature = "afl")]
3pub use afl::fuzz as afl_fuzz;
4#[cfg(feature = "honggfuzz")]
5pub use honggfuzz::fuzz as honggfuzz_fuzz;
6
7// This is our inner harness handler function for the runner.
8// We open the input file and feed the data to the harness closure.
9#[doc(hidden)]
10pub fn run_file<F>(mut closure: F)
11where
12    F: FnMut(&[u8]),
13{
14    use std::{env, fs::File, io::Read};
15    let file_name: String = env::args().nth(1).expect("pass in a file name as argument");
16    println!("Now running {file_name}");
17    let mut buffer: Vec<u8> = Vec::new();
18    let mut file = File::open(file_name).unwrap_or_else(|e| {
19        eprintln!("Could not open file: {e}");
20        std::process::exit(1);
21    });
22    file.read_to_end(&mut buffer).unwrap_or_else(|e| {
23        eprintln!("Could not read file: {e}");
24        std::process::exit(1);
25    });
26    closure(buffer.as_slice());
27}
28
29/// Fuzz a closure-like block of code by passing an object of arbitrary type.
30///
31/// It can handle different types of arguments for the harness closure, including Arbitrary.
32///
33/// See [our examples](https://github.com/srlabs/ziggy/tree/main/examples).
34///
35/// ```no_run
36/// # fn main() {
37///     ziggy::fuzz!(|data: &[u8]| {
38///         if data.len() != 6 {return}
39///         if data[0] != b'q' {return}
40///         if data[1] != b'w' {return}
41///         if data[2] != b'e' {return}
42///         if data[3] != b'r' {return}
43///         if data[4] != b't' {return}
44///         if data[5] != b'y' {return}
45///         panic!("BOOM")
46///     });
47/// # }
48/// ```
49#[macro_export]
50macro_rules! inner_fuzz {
51    (|$buf:ident| $body:block) => {
52        $crate::run_file(|$buf| $body);
53    };
54    (|$buf:ident: &[u8]| $body:block) => {
55        $crate::run_file(|$buf| $body);
56    };
57    (|$buf:ident: $dty: ty| $body:block) => {
58        $crate::run_file(|$buf| {
59            let $buf: $dty = {
60                let mut data = ::arbitrary::Unstructured::new($buf);
61                if let Ok(d) = ::arbitrary::Arbitrary::arbitrary(&mut data).map_err(|_| "") {
62                    d
63                } else {
64                    return;
65                }
66            };
67            $body
68        });
69    };
70}
71
72/// We need this wrapper
73#[macro_export]
74#[cfg(not(any(feature = "afl", feature = "honggfuzz")))]
75macro_rules! fuzz {
76    ( $($x:tt)* ) => {
77        $crate::inner_fuzz!($($x)*);
78    }
79}
80
81#[macro_export]
82#[cfg(feature = "afl")]
83macro_rules! fuzz {
84      ( $($x:tt)* ) => {
85        static USE_ARGS: std::sync::LazyLock<bool> = std::sync::LazyLock::new(|| std::env::args().len() > 1);
86        if *USE_ARGS {
87            $crate::inner_fuzz!($($x)*);
88        } else {
89            $crate::afl_fuzz!($($x)*);
90        }
91    };
92}
93
94#[macro_export]
95#[cfg(all(feature = "honggfuzz", not(feature = "afl")))]
96macro_rules! fuzz {
97    ( $($x:tt)* ) => {
98        loop {
99            $crate::honggfuzz_fuzz!($($x)*);
100        }
101    };
102}