diff --git a/Cargo.toml b/Cargo.toml index adfe66d..d7beb4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ version = "0.4.1" [dependencies] arbitrary = "1" +once_cell = "1" [build-dependencies] cc = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 9262eca..6badc39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ #![deny(missing_docs, missing_debug_implementations)] pub use arbitrary; +use once_cell::sync::OnceCell; extern "C" { // We do not actually cross the FFI bound here. @@ -36,6 +37,9 @@ pub fn test_input_wrap(data: *const u8, size: usize) -> i32 { 0 } +#[doc(hidden)] +pub static RUST_LIBFUZZER_DEBUG_PATH: OnceCell = OnceCell::new(); + #[doc(hidden)] #[export_name = "LLVMFuzzerInitialize"] pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize { @@ -52,6 +56,14 @@ pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize default_hook(panic_info); ::std::process::abort(); })); + + // Initialize the `RUST_LIBFUZZER_DEBUG_PATH` cell with the path so it can be + // reused with little overhead. + if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") { + RUST_LIBFUZZER_DEBUG_PATH + .set(path) + .expect("Since this is initialize it is only called once so can never fail"); + } 0 } @@ -130,7 +142,9 @@ macro_rules! fuzz_target { // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug // formatting of the input to that file. This is only intended for // `cargo fuzz`'s use! - if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") { + + // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization. + if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() { use std::io::Write; let mut file = std::fs::File::create(path) .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file"); @@ -151,7 +165,7 @@ macro_rules! fuzz_target { /// Auto-generated function #[no_mangle] pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) { - use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured}; + use $crate::arbitrary::{Arbitrary, Unstructured}; // Early exit if we don't have enough bytes for the `Arbitrary` // implementation. This helps the fuzzer avoid exploring all the @@ -169,7 +183,9 @@ macro_rules! fuzz_target { // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug // formatting of the input to that file. This is only intended for // `cargo fuzz`'s use! - if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") { + + // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization. + if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() { use std::io::Write; let mut file = std::fs::File::create(path) .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");