cargo-fuzz icon indicating copy to clipboard operation
cargo-fuzz copied to clipboard

Generalize fuzz macro

Open Manishearth opened this issue 7 years ago • 1 comments

Currently a fuzz target looks like

#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate thing;

fuzz_target!(|data: Type| {
    //stuff
});

Ideally, it would instead look like

extern crate thing;

#[macro_use] extern crate arbitrary_macros;

target!(|data: Type| {
    // stuff
});

where the macro introduces the no_main and the libfuzzer_sys.

This means we could use the same script for a quickcheck, or for running with seer

The exact code it expands to can be controlled by a cfg that is a part of the macro expansion. This way we can have cargo-fuzz also do things like cargo fuzz seer name_of_script or cargo fuzz quickcheck name_of_script, which will pass different cfg args to the fuzzer script and do a completely different thing.

Having a common API would be pretty neat, overall. Also makes it easier to be agnostic over the fuzzer.

cc @nagisa @frewsxcv @dwrensha

Manishearth avatar Jun 10 '17 01:06 Manishearth

@PaulGrandperrin, even after seeing https://github.com/rust-fuzz/libfuzzer-sys/pull/33 and https://github.com/rust-fuzz/afl.rs/pull/137, I don't think this should be closed or at least that we can go one step further. If you don't agree, feel free to close it again.

Is there any reason to not also put the extern crate and fn main stuff into a macro that the other fuzzers might also use to present a truly uniform interface?

Let's compare the code you write for the three fuzzers right now:

/// AFL
extern crate afl;

fn main() {
    // … setup …
    afl::read_stdio_bytes(|data|{
        // … your code …
    });
}
/// honggfuzz
#[macro_use] extern crate honggfuzz;

fn main() {
    // … setup …
    loop {
        fuzz!(|data|{
            // … your code …
        })
    }
}
/// libfuzzer after this https://github.com/rust-fuzz/libfuzzer-sys/pull/33
#[macro_use] extern crate libfuzzer_sys;

fn main() {
    // … setup …
    fuzz!(|data: &[u8]| {
        // … your code …
    });
}

This looks all very similar to me, except for the extern crate and the way you separate your fuzz code from your setup code. In an ideal world, cargo-fuzz and the code in fuzz/ should be agnostic to the actual fuzzer used. Imagine:

#[macro_use] extern crate fuzz;

fuzz!(
    optional_name_if_you_want_it_to_differ_from_the_binary_name,
    setup { /* setup is optional */ },
    |data: Type| { /* actual fuzzer code */ }
);

and invoking it with cargo fuzz run name --fuzzer honggfuzz. This is what the issue description also mentions.

killercup avatar Apr 28 '18 17:04 killercup