libfuzzer_sys/lib.rs
1//! Bindings to [libFuzzer](http://llvm.org/docs/LibFuzzer.html): a runtime for
2//! coverage-guided fuzzing.
3//!
4//! See [the `cargo-fuzz`
5//! guide](https://rust-fuzz.github.io/book/cargo-fuzz.html) for a usage
6//! tutorial.
7//!
8//! The main export of this crate is [the `fuzz_target!`
9//! macro](./macro.fuzz_target.html), which allows you to define targets for
10//! libFuzzer to exercise.
11
12#![deny(missing_docs, missing_debug_implementations)]
13
14pub use arbitrary;
15use std::sync::OnceLock;
16
17/// Indicates whether the input should be kept in the corpus or rejected. This
18/// should be returned by your fuzz target. If your fuzz target does not return
19/// a value (i.e., returns `()`), then the input will be kept in the corpus.
20#[derive(Debug)]
21pub enum Corpus {
22 /// Keep the input in the corpus.
23 Keep,
24
25 /// Reject the input and do not keep it in the corpus.
26 Reject,
27}
28
29impl From<()> for Corpus {
30 fn from(_: ()) -> Self {
31 Self::Keep
32 }
33}
34
35impl Corpus {
36 #[doc(hidden)]
37 /// Convert this Corpus result into the [integer codes used by
38 /// `libFuzzer`](https://llvm.org/docs/LibFuzzer.html#rejecting-unwanted-inputs).
39 /// This is -1 for reject, 0 for keep.
40 pub fn to_libfuzzer_code(self) -> i32 {
41 match self {
42 Corpus::Keep => 0,
43 Corpus::Reject => -1,
44 }
45 }
46}
47
48extern "C" {
49 // We do not actually cross the FFI bound here.
50 #[allow(improper_ctypes)]
51 fn rust_fuzzer_test_input(input: &[u8]) -> i32;
52
53 fn LLVMFuzzerMutate(data: *mut u8, size: usize, max_size: usize) -> usize;
54}
55
56/// Do not use; only for LibFuzzer's consumption.
57#[doc(hidden)]
58#[export_name = "LLVMFuzzerTestOneInput"]
59pub unsafe fn test_input_wrap(data: *const u8, size: usize) -> i32 {
60 let test_input = ::std::panic::catch_unwind(|| {
61 let data_slice = ::std::slice::from_raw_parts(data, size);
62 rust_fuzzer_test_input(data_slice)
63 });
64
65 match test_input {
66 Ok(i) => i,
67 Err(_) => {
68 // hopefully the custom panic hook will be called before and abort the
69 // process before the stack frames are unwinded.
70 ::std::process::abort();
71 }
72 }
73}
74
75#[doc(hidden)]
76pub fn rust_libfuzzer_debug_path() -> &'static Option<String> {
77 static RUST_LIBFUZZER_DEBUG_PATH: OnceLock<Option<String>> = OnceLock::new();
78 RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok())
79}
80
81#[doc(hidden)]
82pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
83 // Registers a panic hook that aborts the process before unwinding.
84 // It is useful to abort before unwinding so that the fuzzer will then be
85 // able to analyse the process stack frames to tell different bugs appart.
86 //
87 // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
88 // impossible to build code using compiler plugins with this flag.
89 // We will be able to remove this code when
90 // https://github.com/rust-lang/cargo/issues/5423 is fixed.
91 let default_hook = std::panic::take_hook();
92 std::panic::set_hook(Box::new(move |panic_info| {
93 default_hook(panic_info);
94 std::process::abort();
95 }));
96 0
97}
98
99/// Define a fuzz target.
100///
101/// ## Example
102///
103/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
104/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
105///
106/// ```no_run
107/// #![no_main]
108///
109/// use libfuzzer_sys::fuzz_target;
110///
111/// // Note: `|input|` is short for `|input: &[u8]|`.
112/// fuzz_target!(|input| {
113/// let _result: Result<_, _> = my_crate::parse(input);
114/// });
115/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
116/// ```
117///
118/// ## Rejecting Inputs
119///
120/// It may be desirable to reject some inputs, i.e. to not add them to the
121/// corpus.
122///
123/// For example, when fuzzing an API consisting of parsing and other logic,
124/// one may want to allow only those inputs into the corpus that parse
125/// successfully. To indicate whether an input should be kept in or rejected
126/// from the corpus, return either [Corpus::Keep] or [Corpus::Reject] from your
127/// fuzz target. The default behavior (e.g. if `()` is returned) is to keep the
128/// input in the corpus.
129///
130/// For example:
131///
132/// ```no_run
133/// #![no_main]
134///
135/// use libfuzzer_sys::{Corpus, fuzz_target};
136///
137/// fuzz_target!(|input: String| -> Corpus {
138/// let parts: Vec<&str> = input.splitn(2, '=').collect();
139/// if parts.len() != 2 {
140/// return Corpus::Reject;
141/// }
142///
143/// let key = parts[0];
144/// let value = parts[1];
145/// let _result: Result<_, _> = my_crate::parse(key, value);
146/// Corpus::Keep
147/// });
148/// # mod my_crate { pub fn parse(_key: &str, _value: &str) -> Result<(), ()> { unimplemented!() } }
149/// ```
150///
151/// ## Arbitrary Input Types
152///
153/// The input is a `&[u8]` slice by default, but you can take arbitrary input
154/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
155/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
156/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
157///
158/// For example, if you wanted to take an arbitrary RGB color, you could do the
159/// following:
160///
161/// ```no_run
162/// #![no_main]
163/// # mod foo {
164///
165/// use libfuzzer_sys::{arbitrary::{Arbitrary, Error, Unstructured}, fuzz_target};
166///
167/// #[derive(Debug)]
168/// pub struct Rgb {
169/// r: u8,
170/// g: u8,
171/// b: u8,
172/// }
173///
174/// impl<'a> Arbitrary<'a> for Rgb {
175/// fn arbitrary(raw: &mut Unstructured<'a>) -> Result<Self, Error> {
176/// let mut buf = [0; 3];
177/// raw.fill_buffer(&mut buf)?;
178/// let r = buf[0];
179/// let g = buf[1];
180/// let b = buf[2];
181/// Ok(Rgb { r, g, b })
182/// }
183/// }
184///
185/// // Write a fuzz target that works with RGB colors instead of raw bytes.
186/// fuzz_target!(|color: Rgb| {
187/// my_crate::convert_color(color);
188/// });
189/// # mod my_crate {
190/// # use super::Rgb;
191/// # pub fn convert_color(_: Rgb) {}
192/// # }
193/// # }
194/// ```
195///
196/// You can also enable the `arbitrary` crate's custom derive via this crate's
197/// `"arbitrary-derive"` cargo feature.
198///
199/// ## Init Code
200///
201/// Init code to the fuzz target by using the `init` keyword. This is called once before the fuzzer starts.
202/// Supports short |input| or |input: <type>| syntax.
203///
204/// ```no_run
205/// #![no_main]
206///
207/// use libfuzzer_sys::fuzz_target;
208/// use std::collections::HashSet;
209/// use std::sync::OnceLock;
210///
211/// static DICTIONARY: OnceLock<HashSet<String>> = OnceLock::new();
212///
213/// fuzz_target!(
214/// init: {
215/// let read_dictionary = |_| unimplemented!();
216/// let dictionary = read_dictionary("/usr/share/dict/words");
217/// DICTIONARY.set(dictionary).unwrap();
218/// },
219/// |input| {
220/// // Use the initialized `DICTIONARY` here...
221/// }
222/// );
223/// ```
224///
225#[macro_export]
226macro_rules! fuzz_target {
227 (|$bytes:ident| $body:expr) => {
228 $crate::fuzz_target!(init: (), |$bytes: &[u8]| -> () { $body });
229 };
230
231 (|$bytes:ident: &[u8]| $body:expr) => {
232 $crate::fuzz_target!(init: (), |$bytes: &[u8]| -> () { $body });
233 };
234
235 (|$bytes:ident: &[u8]| -> $rty:ty $body:block) => {
236 $crate::fuzz_target!(init: (), |$bytes: &[u8]| -> $rty { $body });
237 };
238
239 (init: $init:expr, |$bytes:ident| $body:expr) => {
240 $crate::fuzz_target!(init: $init, |$bytes: &[u8]| -> () { $body });
241 };
242
243 (init: $init:expr, |$bytes:ident: &[u8]| $body:expr) => {
244 $crate::fuzz_target!(init: $init, |$bytes: &[u8]| -> () { $body });
245 };
246
247 (init: $init:expr, |$bytes:ident: &[u8]| -> $rty:ty $body:block) => {
248 const _: () = {
249 /// Auto-generated functions
250 /// LLVMFuzzerInitialize is called once before the fuzzer starts.
251 #[no_mangle]
252 pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
253 $crate::initialize(_argc, _argv);
254
255 // Supplied init code
256 $init;
257 0
258 }
259
260 #[no_mangle]
261 pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
262 // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
263 // formatting of the input to that file. This is only intended for
264 // `cargo fuzz`'s use!
265
266 // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
267 if let Some(path) = $crate::rust_libfuzzer_debug_path() {
268 use std::io::Write;
269 let mut file = std::fs::File::create(path)
270 .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
271 writeln!(&mut file, "{:?}", bytes)
272 .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
273 return 0;
274 }
275
276 let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(bytes));
277 result.to_libfuzzer_code()
278 }
279
280 // Split out the actual fuzzer into a separate function which is
281 // tagged as never being inlined. This ensures that if the fuzzer
282 // panics there's at least one stack frame which is named uniquely
283 // according to this specific fuzzer that this is embedded within.
284 //
285 // Systems like oss-fuzz try to deduplicate crashes and without this
286 // panics in separate fuzzers can accidentally appear the same
287 // because each fuzzer will have a function called
288 // `rust_fuzzer_test_input`. By using a normal Rust function here
289 // it's named something like `the_fuzzer_name::_::__libfuzzer_sys_run` which should
290 // ideally help prevent oss-fuzz from deduplicate fuzz bugs across
291 // distinct targets accidentally.
292 #[inline(never)]
293 fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294 $body
295 }
296 };
297 };
298
299 (|$data:ident: $dty:ty| $body:expr) => {
300 $crate::fuzz_target!(init: (), |$data: $dty| -> () { $body });
301 };
302
303 (|$data:ident: $dty:ty| -> $rty:ty $body:block) => {
304 $crate::fuzz_target!(init: (), |$data: $dty| -> $rty { $body });
305 };
306
307 (init: $init:expr, |$data:ident: $dty:ty| $body:expr) => {
308 $crate::fuzz_target!(init: $init, |$data: $dty| -> () { $body });
309 };
310
311 (init: $init:expr, |$data:ident: $dty:ty| -> $rty:ty $body:block) => {
312 const _: () = {
313 /// Auto-generated functions
314 /// LLVMFuzzerInitialize is called once before the fuzzer starts.
315 #[no_mangle]
316 pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
317 $crate::initialize(_argc, _argv);
318
319 // Supplied init code
320 $init;
321 0
322 }
323
324 #[no_mangle]
325 pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
326 use $crate::arbitrary::{Arbitrary, Unstructured};
327
328 // Early exit if we don't have enough bytes for the `Arbitrary`
329 // implementation. This helps the fuzzer avoid exploring all the
330 // different not-enough-input-bytes paths inside the `Arbitrary`
331 // implementation. Additionally, it exits faster, letting the fuzzer
332 // get to longer inputs that actually lead to interesting executions
333 // quicker.
334 if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
335 return -1;
336 }
337
338 let mut u = Unstructured::new(bytes);
339 let data = <$dty as Arbitrary>::arbitrary_take_rest(u);
340
341 // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
342 // formatting of the input to that file. This is only intended for
343 // `cargo fuzz`'s use!
344
345 // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
346 if let Some(path) = $crate::rust_libfuzzer_debug_path() {
347 use std::io::Write;
348 let mut file = std::fs::File::create(path)
349 .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
350 (match data {
351 Ok(data) => writeln!(&mut file, "{:#?}", data),
352 Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
353 })
354 .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
355 return -1;
356 }
357
358 let data = match data {
359 Ok(d) => d,
360 Err(_) => return -1,
361 };
362
363 let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(data));
364 result.to_libfuzzer_code()
365 }
366 // See above for why this is split to a separate function.
367 #[inline(never)]
368 fn __libfuzzer_sys_run($data: $dty) -> $rty {
369 $body
370 }
371 };
372 };
373}
374
375/// Define a custom mutator.
376///
377/// This is optional, and libFuzzer will use its own, default mutation strategy
378/// if this is not provided.
379///
380/// You might consider using a custom mutator when your fuzz target is very
381/// particular about the shape of its input:
382///
383/// * You want to fuzz "deeper" than just the parser.
384/// * The input contains checksums that have to match the hash of some subset of
385/// the data or else the whole thing is invalid, and therefore mutating any of
386/// that subset means you need to recompute the checksums.
387/// * Small random changes to the input buffer make it invalid.
388///
389/// That is, a custom mutator is useful in similar situations where [a `T:
390/// Arbitrary` input type](macro.fuzz_target.html#arbitrary-input-types) is
391/// useful. Note that the two approaches are not mutually exclusive; you can use
392/// whichever is easier for your problem domain or both!
393///
394/// > **Tip:** [The `mutatis` crate](https://docs.rs/mutatis) provides
395/// > abstractions and combinators for writing custom mutators.
396///
397/// ## Implementation Contract
398///
399/// The original, unmodified input is given in `data[..size]`.
400///
401/// You must modify the data in place and return the new size.
402///
403/// The new size should not be greater than `max_size`. If this is not the case,
404/// then the `data` will be truncated to fit within `max_size`. Note that
405/// `max_size < size` is possible when shrinking test cases.
406///
407/// You must produce the same mutation given the same `seed`. Generally, when
408/// choosing what kind of mutation to make or where to mutate, you should start
409/// by creating a random number generator (RNG) that is seeded with the given
410/// `seed` and then consult the RNG whenever making a decision:
411///
412/// ```no_run
413/// #![no_main]
414///
415/// use rand::{rngs::SmallRng, RngExt, SeedableRng};
416///
417/// libfuzzer_sys::fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| {
418/// let mut rng = SmallRng::seed_from_u64(seed as u64);
419///
420/// # let first_mutation = |_, _, _, _| todo!();
421/// # let second_mutation = |_, _, _, _| todo!();
422/// # let third_mutation = |_, _, _, _| todo!();
423/// # let fourth_mutation = |_, _, _, _| todo!();
424/// // Choose which of our four supported kinds of mutations we want to make.
425/// match rng.random_range(0..4) {
426/// 0 => first_mutation(rng, data, size, max_size),
427/// 1 => second_mutation(rng, data, size, max_size),
428/// 2 => third_mutation(rng, data, size, max_size),
429/// 3 => fourth_mutation(rng, data, size, max_size),
430/// _ => unreachable!()
431/// }
432/// });
433/// ```
434///
435/// ## Example: Compression
436///
437/// Consider a simple fuzz target that takes compressed data as input,
438/// decompresses it, and then asserts that the decompressed data doesn't begin
439/// with "boom". It is difficult for `libFuzzer` (or any other fuzzer) to crash
440/// this fuzz target because nearly all mutations it makes will invalidate the
441/// compression format. Therefore, we use a custom mutator that decompresses the
442/// raw input, mutates the decompressed data, and then recompresses it. This
443/// allows `libFuzzer` to quickly discover crashing inputs.
444///
445/// ```no_run
446/// #![no_main]
447///
448/// use flate2::{read::GzDecoder, write::GzEncoder, Compression};
449/// use libfuzzer_sys::{fuzz_mutator, fuzz_target};
450/// use std::io::{Read, Write};
451///
452/// fuzz_target!(|data: &[u8]| {
453/// // Decompress the input data and crash if it starts with "boom".
454/// if let Some(data) = decompress(data) {
455/// if data.starts_with(b"boom") {
456/// panic!();
457/// }
458/// }
459/// });
460///
461/// fuzz_mutator!(
462/// |data: &mut [u8], size: usize, max_size: usize, _seed: u32| {
463/// // Decompress the input data. If that fails, use a dummy value.
464/// let mut decompressed = decompress(&data[..size]).unwrap_or_else(|| b"hi".to_vec());
465///
466/// // Mutate the decompressed data with `libFuzzer`'s default mutator. Make
467/// // the `decompressed` vec's extra capacity available for insertion
468/// // mutations via `resize`.
469/// let len = decompressed.len();
470/// let cap = decompressed.capacity();
471/// decompressed.resize(cap, 0);
472/// let new_decompressed_size = libfuzzer_sys::fuzzer_mutate(&mut decompressed, len, cap);
473///
474/// // Recompress the mutated data.
475/// let compressed = compress(&decompressed[..new_decompressed_size]);
476///
477/// // Copy the recompressed mutated data into `data` and return the new size.
478/// let new_size = std::cmp::min(max_size, compressed.len());
479/// data[..new_size].copy_from_slice(&compressed[..new_size]);
480/// new_size
481/// }
482/// );
483///
484/// fn decompress(compressed_data: &[u8]) -> Option<Vec<u8>> {
485/// let mut decoder = GzDecoder::new(compressed_data);
486/// let mut decompressed = Vec::new();
487/// if decoder.read_to_end(&mut decompressed).is_ok() {
488/// Some(decompressed)
489/// } else {
490/// None
491/// }
492/// }
493///
494/// fn compress(data: &[u8]) -> Vec<u8> {
495/// let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
496/// encoder
497/// .write_all(data)
498/// .expect("writing into a vec is infallible");
499/// encoder.finish().expect("writing into a vec is infallible")
500/// }
501/// ```
502///
503/// This example is inspired by [a similar example from the official `libFuzzer`
504/// docs](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#example-compression).
505///
506/// ## More Example Ideas
507///
508/// * A PNG custom mutator that decodes a PNG, mutates the image, and then
509/// re-encodes the mutated image as a new PNG.
510///
511/// * A [`serde`](https://serde.rs/) custom mutator that deserializes your
512/// structure, mutates it, and then reserializes it.
513///
514/// * A Wasm binary custom mutator that inserts, replaces, and removes a
515/// bytecode instruction in a function's body.
516///
517/// * An HTTP request custom mutator that inserts, replaces, and removes a
518/// header from an HTTP request.
519#[macro_export]
520macro_rules! fuzz_mutator {
521 (
522 |
523 $data:ident : &mut [u8] ,
524 $size:ident : usize ,
525 $max_size:ident : usize ,
526 $seed:ident : u32 $(,)*
527 |
528 $body:block
529 ) => {
530 /// Auto-generated function. Do not use; only for LibFuzzer's
531 /// consumption.
532 #[export_name = "LLVMFuzzerCustomMutator"]
533 #[doc(hidden)]
534 pub unsafe fn rust_fuzzer_custom_mutator(
535 $data: *mut u8,
536 $size: usize,
537 $max_size: usize,
538 $seed: std::os::raw::c_uint,
539 ) -> usize {
540 // Depending on if we are growing or shrinking the test case, `size`
541 // might be larger or smaller than `max_size`. The `data`'s capacity
542 // is the maximum of the two.
543 let len = std::cmp::max($max_size, $size);
544 let $data: &mut [u8] = std::slice::from_raw_parts_mut($data, len);
545
546 // `unsigned int` is generally a `u32`, but not on all targets. Do
547 // an infallible (and potentially lossy, but that's okay because it
548 // preserves determinism) conversion.
549 let $seed = $seed as u32;
550
551 // Define and invoke a new, safe function so that the body doesn't
552 // inherit `unsafe`.
553 fn custom_mutator(
554 $data: &mut [u8],
555 $size: usize,
556 $max_size: usize,
557 $seed: u32,
558 ) -> usize {
559 $body
560 }
561 let new_size = custom_mutator($data, $size, $max_size, $seed);
562
563 // Truncate the new size if it is larger than the max.
564 std::cmp::min(new_size, $max_size)
565 }
566 };
567}
568
569/// The default `libFuzzer` mutator.
570///
571/// You generally don't have to use this at all unless you're defining a
572/// custom mutator with [the `fuzz_mutator!` macro][crate::fuzz_mutator].
573///
574/// Mutates `data[..size]` in place such that the mutated data is no larger than
575/// `max_size` and returns the new size of the mutated data.
576///
577/// To only allow shrinking mutations, make `max_size < size`.
578///
579/// To additionally allow mutations that grow the size of the data, make
580/// `max_size > size`.
581///
582/// Both `size` and `max_size` must be less than or equal to `data.len()`.
583///
584/// # Example
585///
586/// ```no_run
587/// // Create some data in a buffer.
588/// let mut data = vec![0; 128];
589/// data[..b"hello".len()].copy_from_slice(b"hello");
590///
591/// // Ask `libFuzzer` to mutate the data. By setting `max_size` to our buffer's
592/// // full length, we are allowing `libFuzzer` to perform mutations that grow
593/// // the size of the data, such as insertions.
594/// let size = b"hello".len();
595/// let max_size = data.len();
596/// let new_size = libfuzzer_sys::fuzzer_mutate(&mut data, size, max_size);
597///
598/// // Get the mutated data out of the buffer.
599/// let mutated_data = &data[..new_size];
600/// ```
601pub fn fuzzer_mutate(data: &mut [u8], size: usize, max_size: usize) -> usize {
602 assert!(size <= data.len());
603 assert!(max_size <= data.len());
604 let new_size = unsafe { LLVMFuzzerMutate(data.as_mut_ptr(), size, max_size) };
605 assert!(new_size <= data.len());
606 new_size
607}
608
609/// Define a custom cross-over function to combine test cases.
610///
611/// This is optional, and libFuzzer will use its own, default cross-over strategy
612/// if this is not provided. (As of the time of writing, this default strategy
613/// takes alternating byte sequences from the two test cases, to construct the
614/// new one) (see `FuzzerCrossOver.cpp`)
615///
616/// This could potentially be useful if your input is, for instance, a
617/// sequence of fixed sized, multi-byte values and the crossover could then
618/// merge discrete values rather than joining parts of a value.
619///
620/// ## Implementation Contract
621///
622/// The original, read-only inputs are given in the full slices of `data1`, and
623/// `data2` (as opposed to the, potentially, partial slice of `data` in
624/// [the `fuzz_mutator!` macro][crate::fuzz_mutator]).
625///
626/// You must place the new input merged from the two existing inputs' data
627/// into `out` and return the size of the relevant data written to that slice.
628///
629/// The deterministic requirements from [the `fuzz_mutator!` macro][crate::fuzz_mutator]
630/// apply as well to the `seed` parameter
631///
632/// ## Example: Floating-Point Sum NaN
633///
634/// ```no_run
635/// #![no_main]
636///
637/// use libfuzzer_sys::{fuzz_crossover, fuzz_mutator, fuzz_target, fuzzer_mutate};
638/// use rand::{rngs::SmallRng, RngExt, SeedableRng};
639/// use std::mem::size_of;
640///
641/// fuzz_target!(|data: &[u8]| {
642/// let (_, floats, _) = unsafe { data.align_to::<f64>() };
643///
644/// let res = floats
645/// .iter()
646/// .fold(0.0, |a, b| if b.is_nan() { a } else { a + b });
647///
648/// assert!(
649/// !res.is_nan(),
650/// "The sum of the following floats resulted in a NaN: {floats:?}"
651/// );
652/// });
653///
654/// // Inject some ...potentially problematic values to make the example close
655/// // more quickly.
656/// fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| {
657/// let mut rng = SmallRng::seed_from_u64(seed.into());
658///
659/// let (_, floats, _) = unsafe { data[..size].align_to_mut::<f64>() };
660///
661/// let x = rng.random_range(0..=1000);
662/// if x == 0 && !floats.is_empty() {
663/// floats[0] = f64::INFINITY;
664/// } else if x == 1000 && floats.len() > 1 {
665/// floats[1] = f64::NEG_INFINITY;
666/// } else {
667/// return fuzzer_mutate(data, size, max_size);
668/// }
669///
670/// size
671/// });
672///
673/// fuzz_crossover!(|data1: &[u8], data2: &[u8], out: &mut [u8], _seed: u32| {
674/// // Decode each source to see how many floats we can pull with proper
675/// // alignment, and destination as to how many will fit with proper alignment
676/// //
677/// // Keep track of the unaligned prefix to `out`, as we will need to remember
678/// // that those bytes will remain prepended to the actual floats that we
679/// // write into the out buffer.
680/// let (out_pref, out_floats, _) = unsafe { out.align_to_mut::<f64>() };
681/// let (_, d1_floats, _) = unsafe { data1.align_to::<f64>() };
682/// let (_, d2_floats, _) = unsafe { data2.align_to::<f64>() };
683///
684/// // Put into the destination, floats first from data1 then from data2, ...if
685/// // possible given the size of `out`
686/// let mut i: usize = 0;
687/// for float in d1_floats.iter().chain(d2_floats).take(out_floats.len()) {
688/// out_floats[i] = *float;
689/// i += 1;
690/// }
691///
692/// // Now that we have written the true floats, report back to the fuzzing
693/// // engine that we left the unaligned `out` prefix bytes at the beginning of
694/// // `out` and also then the floats that we wrote into the aligned float
695/// // section.
696/// out_pref.len() * size_of::<u8>() + i * size_of::<f64>()
697/// });
698/// ```
699///
700/// This example is a minimized version of [Erik Rigtorp's floating point
701/// summation fuzzing example][1]. A more detailed version of this experiment
702/// can be found in the `example_crossover` directory.
703///
704/// [1]: https://rigtorp.se/fuzzing-floating-point-code/
705#[macro_export]
706macro_rules! fuzz_crossover {
707 (
708 |
709 $data1:ident : &[u8] ,
710 $data2:ident : &[u8] ,
711 $out:ident : &mut [u8] ,
712 $seed:ident : u32 $(,)*
713 |
714 $body:block
715 ) => {
716 /// Auto-generated function. Do not use; only for LibFuzzer's
717 /// consumption.
718 #[export_name = "LLVMFuzzerCustomCrossOver"]
719 #[doc(hidden)]
720 pub unsafe fn rust_fuzzer_custom_crossover(
721 $data1: *const u8,
722 size1: usize,
723 $data2: *const u8,
724 size2: usize,
725 $out: *mut u8,
726 max_out_size: usize,
727 $seed: std::os::raw::c_uint,
728 ) -> usize {
729 let $data1: &[u8] = std::slice::from_raw_parts($data1, size1);
730 let $data2: &[u8] = std::slice::from_raw_parts($data2, size2);
731 let $out: &mut [u8] = std::slice::from_raw_parts_mut($out, max_out_size);
732
733 // `unsigned int` is generally a `u32`, but not on all targets. Do
734 // an infallible (and potentially lossy, but that's okay because it
735 // preserves determinism) conversion.
736 let $seed = $seed as u32;
737
738 // Define and invoke a new, safe function so that the body doesn't
739 // inherit `unsafe`.
740 fn custom_crossover(
741 $data1: &[u8],
742 $data2: &[u8],
743 $out: &mut [u8],
744 $seed: u32,
745 ) -> usize {
746 $body
747 }
748
749 custom_crossover($data1, $data2, $out, $seed)
750 }
751 };
752}