macro_rules! fuzz_target {
(init: $init:expr, |$bytes:ident| $body:expr) => { ... };
(|$bytes:ident| $body:expr) => { ... };
(|$data:ident: &[u8]| $body:expr) => { ... };
(|$data:ident: $dty:ty| $body:expr) => { ... };
(|$data:ident: $dty:ty| -> $rty:ty $body:block) => { ... };
(init: $init:expr, |$data:ident: &[u8]| $body:expr) => { ... };
(init: $init:expr, |$bytes:ident| $body:expr) => { ... };
(init: $init:expr, |$data:ident: $dty:ty| $body:expr) => { ... };
(init: $init:expr, |$data:ident: $dty:ty| -> $rty:ty $body:block) => { ... };
}
Expand description
Define a fuzz target.
§Example
This example takes a &[u8]
slice and attempts to parse it. The parsing
might fail and return an Err
, but it shouldn’t ever panic or segfault.
#![no_main]
use libfuzzer_sys::fuzz_target;
// Note: `|input|` is short for `|input: &[u8]|`.
fuzz_target!(|input| {
let _result: Result<_, _> = my_crate::parse(input);
});
§Rejecting Inputs
It may be desirable to reject some inputs, i.e. to not add them to the corpus.
For example, when fuzzing an API consisting of parsing and other logic,
one may want to allow only those inputs into the corpus that parse
successfully. To indicate whether an input should be kept in or rejected
from the corpus, return either Corpus::Keep or Corpus::Reject from your
fuzz target. The default behavior (e.g. if ()
is returned) is to keep the
input in the corpus.
For example:
#![no_main]
use libfuzzer_sys::{Corpus, fuzz_target};
fuzz_target!(|input: String| -> Corpus {
let parts: Vec<&str> = input.splitn(2, '=').collect();
if parts.len() != 2 {
return Corpus::Reject;
}
let key = parts[0];
let value = parts[1];
let _result: Result<_, _> = my_crate::parse(key, value);
Corpus::Keep
});
§Arbitrary Input Types
The input is a &[u8]
slice by default, but you can take arbitrary input
types, as long as the type implements the arbitrary
crate’s Arbitrary
trait (which is
also re-exported as libfuzzer_sys::arbitrary::Arbitrary
for convenience).
For example, if you wanted to take an arbitrary RGB color, you could do the following:
#![no_main]
use libfuzzer_sys::{arbitrary::{Arbitrary, Error, Unstructured}, fuzz_target};
#[derive(Debug)]
pub struct Rgb {
r: u8,
g: u8,
b: u8,
}
impl<'a> Arbitrary<'a> for Rgb {
fn arbitrary(raw: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut buf = [0; 3];
raw.fill_buffer(&mut buf)?;
let r = buf[0];
let g = buf[1];
let b = buf[2];
Ok(Rgb { r, g, b })
}
}
// Write a fuzz target that works with RGB colors instead of raw bytes.
fuzz_target!(|color: Rgb| {
my_crate::convert_color(color);
});
You can also enable the arbitrary
crate’s custom derive via this crate’s
"arbitrary-derive"
cargo feature.
§Init Code
Init code to the fuzz target by using the init
keyword. This is called once before the fuzzer starts.
Supports short |input| or |input:
#![no_main]
use libfuzzer_sys::fuzz_target;
use std::collections::HashSet;
use std::sync::OnceLock;
static DICTIONARY: OnceLock<HashSet<String>> = OnceLock::new();
fuzz_target!(
init: {
let read_dictionary = |_| unimplemented!();
let dictionary = read_dictionary("/usr/share/dict/words");
DICTIONARY.set(dictionary).unwrap();
},
|input| {
// Use the initialized `DICTIONARY` here...
}
);