1use std::any::{Any, TypeId};
2use std::borrow::Borrow;
3use std::collections::hash_map::DefaultHasher;
4use std::collections::HashMap;
5use std::hash::{Hash, Hasher};
6use std::panic::{catch_unwind, AssertUnwindSafe};
7use std::process::exit;
8use std::result::Result;
9
10use fuzzcheck_common::arg::{Arguments, FuzzerCommand};
11use fuzzcheck_common::{FuzzerEvent, FuzzerStats};
12use libc::{SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGINT, SIGSEGV, SIGTERM, SIGTRAP};
13
14use crate::data_structures::RcSlab;
15use crate::sensors_and_pools::{
16 AndSensorAndPool, NoopSensor, TestFailure, TestFailurePool, TestFailureSensor, UnitPool, TEST_FAILURE,
17};
18use crate::signals_handler::set_signal_handlers;
19use crate::subvalue_provider::{CrossoverSubValueProvider, Generation, SubValueProviderId};
20use crate::traits::{CorpusDelta, Mutator, SaveToStatsFolder, SensorAndPool, Serializer};
21use crate::world::World;
22use crate::{CSVField, SubValueProvider, ToCSV};
23
24static WRITE_STATS_ERROR: &str = "the stats could not be written to the file system";
25static WORLD_NEW_ERROR: &str = "an IO operation failed when setting up the fuzzer";
26static SERIALIZER_FROM_DATA_ERROR: &str = "the file could not be decoded into a valid input";
27static READ_INPUT_FILE_ERROR: &str = "the input file could not be read";
28static SAVE_ARTIFACTS_ERROR: &str = "the artifact could not be saved";
29static UPDATE_CORPUS_ERROR: &str = "the corpus could not be updated on the file system";
30
31static mut DID_FIND_ANY_TEST_FAILURE: bool = false;
32
33#[derive(Debug, Clone)]
43pub struct FuzzingResult<T> {
44 pub found_test_failure: bool,
45 pub reason_for_stopping: ReasonForStopping<T>,
46}
47
48#[derive(Debug, Clone)]
49pub enum ReasonForStopping<T> {
50 TestFailure(T),
51 ExhaustedAllPossibleMutations,
52 MaxIterationsReached,
53 MaxDurationReached,
54}
55
56#[cfg_attr(feature = "serde_json_serializer", derive(serde::Serialize, serde::Deserialize))]
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub struct PoolStorageIndex(usize);
60
61impl PoolStorageIndex {
63 #[coverage(off)]
64 pub fn mock(idx: usize) -> Self {
65 Self(idx)
66 }
67}
68
69enum FuzzerInputIndex<T> {
70 None,
71 Temporary(T),
72 Pool(PoolStorageIndex),
73}
74
75struct FuzzedInputAndSubValueProvider<T, M>
76where
77 T: Clone + 'static,
78 M: Mutator<T>,
79{
80 input: FuzzedInput<T, M>,
81 subvalues: CrossoverSubValueProvider<T, M>,
82}
83
84struct FuzzedInput<T: Clone + 'static, Mut: Mutator<T>> {
89 value: T,
90 cache: Mut::Cache,
91 mutation_step: Mut::MutationStep,
92 generation: Generation,
93}
94impl<T: Clone + 'static, Mut: Mutator<T>> Clone for FuzzedInput<T, Mut> {
95 fn clone(&self) -> Self {
96 Self {
97 value: self.value.clone(),
98 cache: self.cache.clone(),
99 mutation_step: self.mutation_step.clone(),
100 generation: self.generation,
101 }
102 }
103}
104
105impl<T: Clone + 'static, Mut: Mutator<T>> FuzzedInput<T, Mut> {
106 #[coverage(off)]
107 fn new(value: T, cache: Mut::Cache, mutation_step: Mut::MutationStep, generation: Generation) -> Self {
108 Self {
109 value,
110 cache,
111 mutation_step,
112 generation,
113 }
114 }
115
116 #[coverage(off)]
117 fn new_source(&self, m: &Mut, generation: Generation) -> Self {
118 let cache = m.validate_value(&self.value).unwrap();
119 let mutation_step = m.default_mutation_step(&self.value, &cache);
120 Self::new(self.value.clone(), cache, mutation_step, generation)
121 }
122
123 #[coverage(off)]
124 fn complexity(&self, m: &Mut) -> f64 {
125 m.complexity(&self.value, &self.cache)
126 }
127
128 #[coverage(off)]
129 fn mutate(
130 &mut self,
131 m: &Mut,
132 subvalue_provider: &dyn SubValueProvider,
133 max_cplx: f64,
134 ) -> Option<(Mut::UnmutateToken, f64)> {
135 m.ordered_mutate(
136 &mut self.value,
137 &mut self.cache,
138 &mut self.mutation_step,
139 subvalue_provider,
140 max_cplx,
141 )
142 }
143
144 #[coverage(off)]
145 fn unmutate(&mut self, m: &Mut, t: Mut::UnmutateToken) {
146 m.unmutate(&mut self.value, &mut self.cache, t);
147 }
148}
149
150struct FuzzerState<T: Clone + 'static, M: Mutator<T>> {
151 mutator: M,
152 sensor_and_pool: Box<dyn SensorAndPool>,
153 pool_storage: RcSlab<FuzzedInputAndSubValueProvider<T, M>>,
154 arbitrary_step: M::ArbitraryStep,
156 input_idx: FuzzerInputIndex<FuzzedInput<T, M>>,
158 fuzzer_stats: FuzzerStats,
160
161 settings: Arguments,
162 serializer: Box<dyn Serializer<Value = T>>,
163 world: World,
165 rng: fastrand::Rng,
166
167 signal_handler_alt_stack: Option<(*mut u8, std::alloc::Layout)>,
168}
169
170impl<T: Clone + 'static, M: Mutator<T>> Drop for FuzzerState<T, M> {
171 #[coverage(off)]
172 fn drop(&mut self) {
173 unsafe {
174 crate::signals_handler::reset_signal_handlers();
175 if let Some((stack_ptr, stack_layout)) = self.signal_handler_alt_stack {
176 std::alloc::dealloc(stack_ptr, stack_layout);
177 }
178 }
179 }
180}
181
182impl<T: Clone + 'static, M: Mutator<T>> FuzzerState<T, M> {
183 #[coverage(off)]
184 fn get_input<'a>(
185 fuzzer_input_idx: &'a FuzzerInputIndex<FuzzedInput<T, M>>,
186 pool_storage: &'a RcSlab<FuzzedInputAndSubValueProvider<T, M>>,
187 ) -> Option<&'a FuzzedInput<T, M>> {
188 match fuzzer_input_idx {
189 FuzzerInputIndex::None => None,
190 FuzzerInputIndex::Temporary(input) => Some(input),
191 FuzzerInputIndex::Pool(idx) => Some(&pool_storage[idx.0].input),
192 }
193 }
194}
195
196#[coverage(off)]
197fn update_fuzzer_stats(stats: &mut FuzzerStats, world: &mut World) {
198 let microseconds = world.elapsed_time_since_last_checkpoint();
199 let nbr_runs = stats.total_number_of_runs - stats.number_of_runs_since_last_reset_time;
200 let nbr_runs_times_million = nbr_runs * 1_000_000;
201 if microseconds != 0 {
202 stats.exec_per_s = nbr_runs_times_million / microseconds;
203 }
204 if microseconds > 1_000_000 {
205 world.set_checkpoint_instant();
206 stats.number_of_runs_since_last_reset_time = stats.total_number_of_runs;
207 }
208}
209
210impl<T: Clone + 'static, M: Mutator<T>> SaveToStatsFolder for FuzzerState<T, M>
211where
212 Self: 'static,
213{
214 #[coverage(off)]
215 fn save_to_stats_folder(&self) -> Vec<(std::path::PathBuf, Vec<u8>)> {
216 let mut contents = self.sensor_and_pool.save_to_stats_folder();
217 contents.extend(self.world.save_to_stats_folder());
218 contents
219 }
220}
221
222impl<T: Clone + 'static, M: Mutator<T>> FuzzerState<T, M>
223where
224 Self: 'static,
225{
226 #[coverage(off)]
227 fn write_stats(&mut self) -> Result<(), std::io::Error> {
228 self.world.write_stats_content(self.save_to_stats_folder())
229 }
230
231 #[coverage(off)]
232 fn receive_signal(&mut self, signal: i32) -> ! {
233 self.world.report_event(
234 FuzzerEvent::CaughtSignal(signal as i32),
235 Some((&self.fuzzer_stats, self.sensor_and_pool.stats().as_ref())),
236 );
237
238 match signal {
239 SIGABRT | SIGBUS | SIGSEGV | SIGFPE | SIGALRM | SIGTRAP => {
240 if let Some(input) = Self::get_input(&self.input_idx, &self.pool_storage) {
241 let input = input.new_source(&self.mutator, Generation(0));
242 let cplx = input.complexity(&self.mutator);
243 let content = self.serializer.to_data(&input.value);
244 let _ = self.world.save_artifact(content, cplx, self.serializer.extension());
245 self.write_stats().expect(WRITE_STATS_ERROR);
246 exit(TerminationStatus::Crash as i32);
247 } else {
248 self.world.report_event(
249 FuzzerEvent::CrashNoInput,
250 Some((&self.fuzzer_stats, self.sensor_and_pool.stats().as_ref())),
251 );
252 exit(TerminationStatus::Crash as i32);
253 }
254 }
255 SIGINT | SIGTERM => {
256 self.write_stats().expect(WRITE_STATS_ERROR);
257 self.world.stop()
258 }
259 _ => exit(TerminationStatus::Unknown as i32),
260 }
261 }
262 #[coverage(off)]
263 fn arbitrary_input(&mut self) -> Option<(FuzzedInput<T, M>, f64)> {
264 if let Some((v, cplx)) = self
265 .mutator
266 .ordered_arbitrary(&mut self.arbitrary_step, self.settings.max_input_cplx)
267 {
268 let cache = self.mutator.validate_value(&v).unwrap();
269 let step = self.mutator.default_mutation_step(&v, &cache);
270 Some((FuzzedInput::new(v, cache, step, Generation(0)), cplx))
271 } else {
272 None
273 }
274 }
275 #[coverage(off)]
276 unsafe fn set_up_signal_handler(&mut self) {
277 let ptr = self as *mut Self;
278 let (stack_ptr, stack_size) = set_signal_handlers(
279 #[coverage(off)]
280 move |sig| (*ptr).receive_signal(sig),
281 );
282 self.signal_handler_alt_stack = Some((stack_ptr, stack_size));
283 }
284}
285
286pub struct Fuzzer<T, M>
287where
288 T: Clone + 'static,
289 M: Mutator<T>,
290 Self: 'static,
291{
292 state: FuzzerState<T, M>,
293 test: Box<dyn Fn(&T) -> bool>,
294}
295
296impl<T, M> Fuzzer<T, M>
297where
298 T: Clone + 'static,
299 M: Mutator<T>,
300 Self: 'static,
301{
302 #[coverage(off)]
303 fn new(
304 test: Box<dyn Fn(&T) -> bool>,
305 mutator: M,
306 serializer: Box<dyn Serializer<Value = T>>,
307 sensor_and_pool: Box<dyn SensorAndPool>,
308 settings: Arguments,
309 world: World,
310 ) -> Self {
311 let arbitrary_step = mutator.default_arbitrary_step();
312 Fuzzer {
313 state: FuzzerState {
314 sensor_and_pool,
315 pool_storage: RcSlab::new(),
316 mutator,
317 arbitrary_step,
318 input_idx: FuzzerInputIndex::None,
319 fuzzer_stats: FuzzerStats::default(),
320 settings,
321 serializer,
322 world,
323 rng: fastrand::Rng::new(),
324 signal_handler_alt_stack: None,
325 },
326 test,
327 }
328 }
329
330 #[coverage(off)]
331 fn test_and_process_input(&mut self, cplx: f64) -> Result<(), ReasonForStopping<T>> {
332 let Fuzzer {
333 state:
334 FuzzerState {
335 mutator,
336 sensor_and_pool,
337 pool_storage,
338 input_idx,
339 fuzzer_stats,
340 serializer,
341 world,
342 settings,
343 ..
344 },
345 test,
346 ..
347 } = self;
348
349 let input = FuzzerState::<T, M>::get_input(input_idx, pool_storage).unwrap();
351
352 std::panic::set_hook(Box::new(
353 #[coverage(off)]
354 move |panic_info| {
355 let mut hasher = DefaultHasher::new();
356 panic_info.location().hash(&mut hasher);
357 unsafe {
358 TEST_FAILURE = Some(TestFailure {
359 display: format!("{}", panic_info),
360 id: hasher.finish(),
361 });
362 }
363 },
364 ));
365 if settings.detect_infinite_loop {
366 let _old_time_left = unsafe { libc::alarm(1) };
367 }
380 sensor_and_pool.start_recording();
381 let result = catch_unwind(AssertUnwindSafe(
382 #[coverage(off)]
383 || (test)(input.value.borrow()),
384 ));
385
386 let _ = std::panic::take_hook();
387 let test_failure = match result {
388 Ok(false) => unsafe {
389 TEST_FAILURE = Some(TestFailure {
390 display: "test function returned false".to_string(),
391 id: 0,
392 });
393 true
394 },
395 Err(_) => {
396 true
399 }
400 Ok(true) => false,
401 };
402 if test_failure {
403 unsafe {
404 DID_FIND_ANY_TEST_FAILURE = true;
405 }
406 }
407 sensor_and_pool.stop_recording();
408 if test_failure && self.state.settings.stop_after_first_failure {
409 let serialized_input = serializer.to_data(&input.value);
410 self.state
411 .world
412 .save_artifact(serialized_input, cplx, serializer.extension())
413 .expect(SAVE_ARTIFACTS_ERROR);
414 return Err(ReasonForStopping::TestFailure(input.value.clone()));
415 }
416
417 fuzzer_stats.total_number_of_runs += 1;
418
419 let input_id = PoolStorageIndex(pool_storage.next_slot());
420
421 let deltas = sensor_and_pool.process(input_id, cplx);
422
423 if !deltas.is_empty() {
424 let add_ref_count = deltas.iter().fold(
425 0,
426 #[coverage(off)]
427 |acc, delta| if delta.add { acc + 1 } else { acc },
428 );
429 update_fuzzer_stats(fuzzer_stats, world);
430 let event = CorpusDelta::fuzzer_event(&deltas);
431 let content = if add_ref_count > 0 {
432 serializer.to_data(&input.value)
433 } else {
434 vec![]
435 };
436 world
437 .update_corpus(input_id, content, &deltas, serializer.extension())
438 .expect(UPDATE_CORPUS_ERROR);
439 world.report_event(event, Some((fuzzer_stats, sensor_and_pool.stats().as_ref())));
440 if add_ref_count > 0 {
441 let generation = Generation(fuzzer_stats.total_number_of_runs);
442 let input = input.new_source(mutator, generation);
443 let serialised = String::from_utf8(serializer.to_data(&input.value)).unwrap();
445 assert!(
446 (input.complexity(mutator) - cplx).abs() < 0.01,
447 "The mutator used by the fuzz test does not evaluate the complexity of the test cases consistently.
448 This is a bug in the implementation of {}
449 =============
450
451 {serialised}
452
453 =============
454 ",
455 std::any::type_name::<M>()
456 );
457
458 let mut subvalues: HashMap<TypeId, Vec<(*const dyn Any, f64)>> = HashMap::default();
459
460 let mut act_on_subvalue = #[coverage(off)]
461 |subvalue: &dyn Any, complexity| {
462 subvalues
463 .entry(subvalue.type_id())
464 .or_default()
465 .push((subvalue as *const _, complexity));
466 };
467
468 mutator.visit_subvalues(&input.value, &input.cache, &mut act_on_subvalue);
469 let storage_idx_1 = pool_storage.next_slot();
470 let subvalues = CrossoverSubValueProvider::new(
471 SubValueProviderId {
472 idx: storage_idx_1,
473 generation,
474 },
475 &input.value,
476 &input.cache,
477 mutator,
478 );
479 let stored_input = FuzzedInputAndSubValueProvider { input, subvalues };
480 let storage_idx_2 = pool_storage.insert(stored_input, add_ref_count);
481 assert_eq!(storage_idx_1, storage_idx_2);
482 }
483 for delta in deltas {
484 for r in delta.remove {
485 pool_storage.remove(r.0);
486 }
487 }
488 }
489
490 Ok(())
491 }
492
493 #[coverage(off)]
494 fn get_input_and_subvalue_provider<'a>(
495 pool_storage: &'a mut RcSlab<FuzzedInputAndSubValueProvider<T, M>>,
496 sensor_and_pool: &mut dyn SensorAndPool,
497 rng: &fastrand::Rng,
498 idx: PoolStorageIndex,
499 ) -> (&'a mut FuzzedInput<T, M>, &'a (impl SubValueProvider + 'a)) {
500 let idx_cross = sensor_and_pool.get_random_index().unwrap();
501
502 if idx == idx_cross || rng.u8(..5) == 0 {
503 let FuzzedInputAndSubValueProvider { input, subvalues } = &mut pool_storage[idx.0];
504 (input, subvalues)
505 } else {
506 let (input, FuzzedInputAndSubValueProvider { subvalues, .. }) =
508 pool_storage.get_mut_and_ref(idx.0, idx_cross.0).unwrap();
509 (&mut input.input, subvalues)
510 }
511 }
512
513 #[coverage(off)]
514 fn process_next_input(&mut self) -> Result<(), ReasonForStopping<T>> {
515 let FuzzerState {
516 pool_storage,
517 sensor_and_pool,
518 input_idx,
519 mutator,
520 settings,
521 rng,
522 fuzzer_stats,
523 world,
524 ..
525 } = &mut self.state;
526
527 if let Some(idx) = sensor_and_pool.get_random_index() {
528 *input_idx = FuzzerInputIndex::Pool(idx);
529 let (input, subvalue_provider) =
530 Self::get_input_and_subvalue_provider(pool_storage, sensor_and_pool.as_mut(), rng, idx);
531 let generation = input.generation;
532 if let Some((unmutate_token, complexity)) =
533 input.mutate(mutator, subvalue_provider, settings.max_input_cplx)
534 {
535 if complexity < self.state.settings.max_input_cplx {
537 self.test_and_process_input(complexity)?;
538 }
539
540 if let Some(input) = self.state.pool_storage.get_mut(idx.0).map(
542 #[coverage(off)]
543 |x| &mut x.input,
544 ) && input.generation == generation
545 {
546 input.unmutate(&self.state.mutator, unmutate_token);
547 }
548
549 Ok(())
550 } else {
551 world.report_event(FuzzerEvent::End, Some((fuzzer_stats, sensor_and_pool.stats().as_ref())));
552 Err(ReasonForStopping::ExhaustedAllPossibleMutations)
553 }
554 } else if let Some((input, cplx)) = self.state.arbitrary_input() {
555 self.state.input_idx = FuzzerInputIndex::Temporary(input);
556
557 if cplx < self.state.settings.max_input_cplx {
558 self.test_and_process_input(cplx)?;
559 }
560
561 Ok(())
562 } else {
563 self.state.world.report_event(
564 FuzzerEvent::End,
565 Some((&self.state.fuzzer_stats, self.state.sensor_and_pool.stats().as_ref())),
566 );
567 Err(ReasonForStopping::ExhaustedAllPossibleMutations)
568 }
569 }
570
571 #[coverage(off)]
572 fn process_initial_inputs(&mut self) -> Result<(), ReasonForStopping<T>> {
573 let mut inputs: Vec<FuzzedInput<T, M>> = self
574 .state
575 .world
576 .read_input_corpus()
577 .expect(READ_INPUT_FILE_ERROR)
578 .into_iter()
579 .filter_map(
580 #[coverage(off)]
581 |value| {
582 let value = self.state.serializer.from_data(&value)?;
583 let cache = self.state.mutator.validate_value(&value)?;
584 let mutation_step = self.state.mutator.default_mutation_step(&value, &cache);
585 Some(FuzzedInput::new(value, cache, mutation_step, Generation(0)))
586 },
587 )
588 .collect();
589
590 for _ in 0..100 {
591 if let Some((input, _)) = self.state.arbitrary_input() {
592 inputs.push(input);
593 } else {
594 break;
595 }
596 }
597 inputs.retain(
598 #[coverage(off)]
599 |i| i.complexity(&self.state.mutator) <= self.state.settings.max_input_cplx,
600 );
601 self.state.world.set_checkpoint_instant();
604 for input in inputs {
605 let cplx = input.complexity(&self.state.mutator);
606 self.state.input_idx = FuzzerInputIndex::Temporary(input);
607 self.test_and_process_input(cplx)?;
608 }
609
610 Ok(())
611 }
612
613 #[coverage(off)]
614 fn main_loop(&mut self, minify: bool) -> Result<!, ReasonForStopping<T>> {
615 self.state.world.report_event(
616 FuzzerEvent::Start,
617 Some((&self.state.fuzzer_stats, self.state.sensor_and_pool.stats().as_ref())),
618 );
619 if !minify {
620 self.process_initial_inputs()?;
621 self.state.world.report_event(
622 FuzzerEvent::DidReadCorpus,
623 Some((&self.state.fuzzer_stats, self.state.sensor_and_pool.stats().as_ref())),
624 );
625 }
626
627 self.state.world.set_checkpoint_instant();
628 let mut next_milestone = (self.state.fuzzer_stats.total_number_of_runs + 10) * 2;
629 loop {
630 let duration_since_beginning = self.state.world.elapsed_time_since_start();
631 if duration_since_beginning > self.state.settings.maximum_duration {
632 return Err(ReasonForStopping::MaxDurationReached);
633 }
634 if self.state.fuzzer_stats.total_number_of_runs >= self.state.settings.maximum_iterations {
635 return Err(ReasonForStopping::MaxIterationsReached);
636 }
637 self.process_next_input()?;
638 if self.state.fuzzer_stats.total_number_of_runs >= next_milestone {
639 update_fuzzer_stats(&mut self.state.fuzzer_stats, &mut self.state.world);
640 self.state.world.report_event(
641 FuzzerEvent::Pulse,
642 Some((&self.state.fuzzer_stats, self.state.sensor_and_pool.stats().as_ref())),
643 );
644 next_milestone = self.state.fuzzer_stats.total_number_of_runs * 2;
645 }
646 }
647 }
648}
649
650pub enum TerminationStatus {
651 Success = 0,
652 Crash = 1,
653 TestFailure = 2,
654 Unknown = 3,
655}
656
657#[coverage(off)]
658pub fn launch<T, M>(
659 test: Box<dyn Fn(&T) -> bool>,
660 mutator: M,
661 serializer: Box<dyn Serializer<Value = T>>,
662 sensor_and_pool: Box<dyn SensorAndPool>,
663 mut args: Arguments,
664) -> FuzzingResult<T>
665where
666 T: Clone + 'static,
667 M: Mutator<T>,
668 Fuzzer<T, M>: 'static,
669{
670 let command = &args.command;
671 let reason_for_stopping = match command {
672 FuzzerCommand::Fuzz => {
673 if !args.stop_after_first_failure {
674 let test_failure_sensor = TestFailureSensor::default();
675 let test_failure_pool = TestFailurePool::new("test_failures");
676 let sensor_and_pool = AndSensorAndPool::new(
677 sensor_and_pool,
678 Box::new((test_failure_sensor, test_failure_pool)),
679 10.0,
680 1.0,
681 );
682 let mut fuzzer = Fuzzer::new(
683 test,
684 mutator,
685 serializer,
686 Box::new(sensor_and_pool),
687 args.clone(),
688 World::new(args.clone()).expect(WORLD_NEW_ERROR),
689 );
690
691 let mut stats_headers = vec![CSVField::String("time".to_string())];
692 stats_headers.extend(fuzzer.state.fuzzer_stats.csv_headers());
693 stats_headers.extend(fuzzer.state.sensor_and_pool.stats().csv_headers());
694 fuzzer
695 .state
696 .world
697 .append_stats_file(&stats_headers)
698 .expect(WRITE_STATS_ERROR);
699 unsafe { fuzzer.state.set_up_signal_handler() };
700
701 let reason_for_stopping = fuzzer.main_loop(false).unwrap_err();
702 fuzzer.state.write_stats().expect(WRITE_STATS_ERROR);
703
704 reason_for_stopping
705 } else {
706 let mut fuzzer = Fuzzer::new(
707 test,
708 mutator,
709 serializer,
710 sensor_and_pool,
711 args.clone(),
712 World::new(args.clone()).expect(WORLD_NEW_ERROR),
713 );
714 unsafe { fuzzer.state.set_up_signal_handler() };
715
716 let mut stats_headers = vec![CSVField::String("time".to_string())];
717 stats_headers.extend(fuzzer.state.fuzzer_stats.csv_headers());
718 stats_headers.extend(fuzzer.state.sensor_and_pool.stats().csv_headers());
719 fuzzer
720 .state
721 .world
722 .append_stats_file(&stats_headers)
723 .expect(WRITE_STATS_ERROR);
724 let reason_for_stopping = fuzzer.main_loop(false).unwrap_err();
725 fuzzer.state.write_stats().expect(WRITE_STATS_ERROR);
726
727 reason_for_stopping
728 }
729 }
730 FuzzerCommand::MinifyInput { input_file } => {
731 let world = World::new(args.clone()).expect(WORLD_NEW_ERROR);
732 let value = world.read_input_file(input_file).expect(READ_INPUT_FILE_ERROR);
733 let value = serializer.from_data(&value).expect(SERIALIZER_FROM_DATA_ERROR);
734 if let Some(cache) = mutator.validate_value(&value) {
735 let mutation_step = mutator.default_mutation_step(&value, &cache);
736 args.max_input_cplx = mutator.complexity(&value, &cache) - 0.01;
737
738 let noop_sensor = NoopSensor;
739 let unit_pool = UnitPool::new(PoolStorageIndex(0));
740 let sensor_and_pool =
741 AndSensorAndPool::new(sensor_and_pool, Box::new((noop_sensor, unit_pool)), 1.0, 100.0);
746 let mut fuzzer = Fuzzer::new(
747 test,
748 mutator,
749 serializer,
750 Box::new(sensor_and_pool),
751 args.clone(),
752 world,
753 );
754
755 let mut subvalues: HashMap<TypeId, Vec<(*const dyn Any, f64)>> = HashMap::default();
756
757 let mut act_on_subvalue = #[coverage(off)]
758 |subvalue: &dyn Any, complexity| {
759 subvalues
760 .entry(subvalue.type_id())
761 .or_default()
762 .push((subvalue as *const _, complexity));
763 };
764
765 fuzzer
766 .state
767 .mutator
768 .visit_subvalues(&value, &cache, &mut act_on_subvalue);
769 let storage_idx_1 = fuzzer.state.pool_storage.next_slot();
770 let generation = Generation(0);
771 let subvalues = CrossoverSubValueProvider::new(
772 SubValueProviderId {
773 idx: storage_idx_1,
774 generation,
775 },
776 &value,
777 &cache,
778 &fuzzer.state.mutator,
779 );
780 let stored_input = FuzzedInputAndSubValueProvider {
781 input: FuzzedInput::new(value, cache, mutation_step, generation),
782 subvalues,
783 };
784 let storage_idx_2 = fuzzer.state.pool_storage.insert(stored_input, 1);
785
786 assert_eq!(storage_idx_1, storage_idx_2);
787
788 unsafe { fuzzer.state.set_up_signal_handler() };
789
790 fuzzer.main_loop(true).unwrap_err()
791 } else {
792 panic!("A value in the input corpus is invalid.");
795 }
796 }
797 FuzzerCommand::Read { input_file } => {
798 let mut world = World::new(args.clone()).expect(WORLD_NEW_ERROR);
800 let value = world.read_input_file(input_file).expect(READ_INPUT_FILE_ERROR);
801 let value = serializer.from_data(&value).expect(SERIALIZER_FROM_DATA_ERROR);
802 if let Some(cache) = mutator.validate_value(&value) {
803 let mutation_step = mutator.default_mutation_step(&value, &cache);
804 let input = FuzzedInput::new(value, cache, mutation_step, Generation(0));
805 let cplx = input.complexity(&mutator);
806
807 if args.detect_infinite_loop {
808 let _old_time_left = unsafe { libc::alarm(1) };
809 }
822
823 let result = catch_unwind(AssertUnwindSafe(
824 #[coverage(off)]
825 || (test)(input.value.borrow()),
826 ));
827
828 if result.is_err() || !result.unwrap() {
829 world.report_event(FuzzerEvent::TestFailure, None);
830 let content = serializer.to_data(&input.value);
831 world
832 .save_artifact(content, cplx, serializer.extension())
833 .expect(SAVE_ARTIFACTS_ERROR);
834 exit(TerminationStatus::TestFailure as i32);
839 } else {
840 exit(TerminationStatus::Success as i32);
841 }
842 } else {
843 panic!("A value in the input corpus is invalid.");
845 }
846 }
847 };
848 let _ = std::panic::take_hook();
849
850 let found_test_failure =
851 unsafe { matches!(reason_for_stopping, ReasonForStopping::TestFailure(_)) || DID_FIND_ANY_TEST_FAILURE };
852
853 FuzzingResult {
854 found_test_failure,
855 reason_for_stopping,
856 }
857}