1#[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 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 pub fn honggfuzz_main(a: c_int, b: *const *const c_char) -> c_int;
115 }
116
117 pub unsafe fn exec<Args: Iterator<Item = String>>(args: Args) {
123 let args = args
125 .map(|arg| CString::new(arg).unwrap())
126 .collect::<Vec<_>>();
127
128 let c_args = args
130 .iter()
131 .map(|arg| arg.as_ptr())
132 .chain(Some(core::ptr::null())) .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::*;