bolero_honggfuzz/
lib.rs

1//! honggfuzz plugin for bolero
2//!
3//! This crate should not be used directly. Instead, use `bolero`.
4
5#[doc(hidden)]
6#[cfg(any(test, all(feature = "lib", fuzzing_honggfuzz)))]
7pub mod fuzzer {
8    use bolero_engine::{
9        driver, input, panic as bolero_panic, Engine, Never, ScopedEngine, TargetLocation, Test,
10    };
11    use std::{mem::MaybeUninit, slice};
12
13    extern "C" {
14        fn HF_ITER(buf_ptr: *mut *const u8, len_ptr: *mut usize);
15    }
16
17    #[derive(Debug, Default)]
18    pub struct HonggfuzzEngine {}
19
20    impl HonggfuzzEngine {
21        pub fn new(_location: TargetLocation) -> Self {
22            Self::default()
23        }
24    }
25
26    impl<T: Test> Engine<T> for HonggfuzzEngine {
27        type Output = Never;
28
29        fn run(self, mut test: T, options: driver::Options) -> Self::Output {
30            bolero_panic::set_hook();
31
32            let mut input = HonggfuzzInput::new(options);
33
34            loop {
35                if test.test(&mut input.test_input()).is_err() {
36                    std::process::abort();
37                }
38            }
39        }
40    }
41
42    impl ScopedEngine for HonggfuzzEngine {
43        type Output = Never;
44
45        fn run<F, R>(self, mut test: F, options: driver::Options) -> Self::Output
46        where
47            F: FnMut() -> R + core::panic::RefUnwindSafe,
48            R: bolero_engine::IntoResult,
49        {
50            bolero_panic::set_hook();
51
52            // extend the lifetime of the bytes so it can be stored in local storage
53            let driver = bolero_engine::driver::bytes::Driver::new(&[][..], &options);
54            let driver = bolero_engine::driver::object::Object(driver);
55            let mut driver = Box::new(driver);
56
57            let mut input = HonggfuzzInput::new(options);
58
59            loop {
60                driver.reset(input.get_slice(), &input.options);
61                let (drv, result) = bolero_engine::any::run(driver, &mut test);
62                driver = drv;
63
64                if result.is_err() {
65                    std::process::abort();
66                }
67            }
68        }
69    }
70
71    pub struct HonggfuzzInput {
72        buf_ptr: MaybeUninit<*const u8>,
73        len_ptr: MaybeUninit<usize>,
74        options: driver::Options,
75    }
76
77    impl HonggfuzzInput {
78        fn new(options: driver::Options) -> Self {
79            Self {
80                options,
81                buf_ptr: MaybeUninit::uninit(),
82                len_ptr: MaybeUninit::uninit(),
83            }
84        }
85
86        fn get_slice(&mut self) -> &'static [u8] {
87            unsafe {
88                HF_ITER(self.buf_ptr.as_mut_ptr(), self.len_ptr.as_mut_ptr());
89                slice::from_raw_parts(self.buf_ptr.assume_init(), self.len_ptr.assume_init())
90            }
91        }
92
93        fn test_input(&mut self) -> input::Bytes {
94            let input = self.get_slice();
95            input::Bytes::new(input, &self.options)
96        }
97    }
98}
99
100#[doc(hidden)]
101#[cfg(all(feature = "lib", fuzzing_honggfuzz))]
102pub use fuzzer::*;
103
104#[doc(hidden)]
105#[cfg(feature = "bin")]
106pub mod bin {
107    use std::{
108        ffi::CString,
109        os::raw::{c_char, c_int},
110    };
111
112    extern "C" {
113        // entrypoint for honggfuzz
114        pub fn honggfuzz_main(a: c_int, b: *const *const c_char) -> c_int;
115    }
116
117    /// Should only be used by `cargo-bolero`
118    ///
119    /// # Safety
120    ///
121    /// Use `cargo-bolero`
122    pub unsafe fn exec<Args: Iterator<Item = String>>(args: Args) {
123        // create a vector of zero terminated strings
124        let args = args
125            .map(|arg| CString::new(arg).unwrap())
126            .collect::<Vec<_>>();
127
128        // convert the strings to raw pointers
129        let c_args = args
130            .iter()
131            .map(|arg| arg.as_ptr())
132            .chain(Some(core::ptr::null())) // add a null pointer to the end
133            .collect::<Vec<_>>();
134
135        let status = honggfuzz_main(args.len() as c_int, c_args.as_ptr());
136        if status != 0 {
137            std::process::exit(status);
138        }
139    }
140}
141
142#[doc(hidden)]
143#[cfg(feature = "bin")]
144pub use bin::*;