1#[doc(hidden)]
6#[cfg(any(test, all(feature = "lib", fuzzing_afl)))]
7pub mod fuzzer {
8 use bolero_engine::{driver, input, panic, Engine, Never, ScopedEngine, TargetLocation, Test};
9 use std::io::Read;
10
11 extern "C" {
12 fn __afl_persistent_loop(counter: usize) -> isize;
14 fn __afl_manual_init();
15 }
16
17 #[used]
18 static PERSIST_MARKER: &str = "##SIG_AFL_PERSISTENT##\0";
19
20 #[used]
21 static DEFERED_MARKER: &str = "##SIG_AFL_DEFER_FORKSRV##\0";
22
23 #[derive(Debug, Default)]
24 pub struct AflEngine {}
25
26 impl AflEngine {
27 pub fn new(_location: TargetLocation) -> Self {
28 Self::default()
29 }
30 }
31
32 impl<T: Test> Engine<T> for AflEngine
33 where
34 T::Value: core::fmt::Debug,
35 {
36 type Output = Never;
37
38 fn run(self, mut test: T, options: driver::Options) -> Self::Output {
39 panic::set_hook();
40
41 let mut input = AflInput::new(options);
42
43 unsafe {
44 __afl_manual_init();
45 }
46
47 while unsafe { __afl_persistent_loop(1000) } != 0 {
48 if test.test(&mut input.test_input()).is_err() {
49 std::process::abort();
50 }
51 }
52
53 std::process::exit(0);
54 }
55 }
56
57 impl ScopedEngine for AflEngine {
58 type Output = Never;
59
60 fn run<F, R>(self, mut test: F, options: driver::Options) -> Self::Output
61 where
62 F: FnMut() -> R + core::panic::RefUnwindSafe,
63 R: bolero_engine::IntoResult,
64 {
65 panic::set_hook();
66
67 let driver = bolero_engine::driver::bytes::Driver::new(vec![], &options);
69 let driver = bolero_engine::driver::object::Object(driver);
70 let mut driver = Box::new(driver);
71
72 let mut input = AflInput::new(options);
73
74 unsafe {
75 __afl_manual_init();
76 }
77
78 while unsafe { __afl_persistent_loop(1000) } != 0 {
79 input.reset();
80 let bytes = core::mem::take(&mut input.input);
81 let tmp = driver.reset(bytes, &input.options);
82 let (drv, result) = bolero_engine::any::run(driver, &mut test);
83 driver = drv;
84 input.input = driver.reset(tmp, &input.options);
85
86 if result.is_err() {
87 std::process::abort();
88 }
89 }
90
91 std::process::exit(0);
92 }
93 }
94
95 #[derive(Debug)]
96 pub struct AflInput {
97 options: driver::Options,
98 input: Vec<u8>,
99 }
100
101 impl AflInput {
102 fn new(options: driver::Options) -> Self {
103 Self {
104 options,
105 input: vec![],
106 }
107 }
108
109 fn reset(&mut self) {
110 self.input.clear();
111 std::io::stdin()
112 .read_to_end(&mut self.input)
113 .expect("could not read next input");
114 }
115
116 fn test_input(&mut self) -> input::Bytes {
117 self.reset();
118 input::Bytes::new(&self.input, &self.options)
119 }
120 }
121}
122
123#[doc(hidden)]
124#[cfg(all(feature = "lib", fuzzing_afl))]
125pub use fuzzer::*;
126
127#[doc(hidden)]
128#[cfg(feature = "bin")]
129pub mod bin {
130 use std::{
131 ffi::CString,
132 os::raw::{c_char, c_int},
133 };
134
135 extern "C" {
136 pub fn afl_fuzz_main(a: c_int, b: *const *const c_char) -> c_int;
138 }
139
140 pub unsafe fn exec<Args: Iterator<Item = String>>(args: Args) {
146 let args = args
148 .map(|arg| CString::new(arg).unwrap())
149 .collect::<Vec<_>>();
150
151 let c_args = args
153 .iter()
154 .map(|arg| arg.as_ptr())
155 .chain(Some(core::ptr::null())) .collect::<Vec<_>>();
157
158 let status = afl_fuzz_main(args.len() as c_int, c_args.as_ptr());
159 if status != 0 {
160 std::process::exit(status);
161 }
162 }
163}
164
165#[doc(hidden)]
166#[cfg(feature = "bin")]
167pub use bin::*;