Coverage Report

Created: 2025-07-11 07:25

/rust/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.10/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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
14
pub use arbitrary;
15
use 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)]
21
pub 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
29
impl From<()> for Corpus {
30
24.6k
    fn from(_: ()) -> Self {
31
24.6k
        Self::Keep
32
24.6k
    }
33
}
34
35
impl 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
24.6k
    pub fn to_libfuzzer_code(self) -> i32 {
41
24.6k
        match self {
42
24.6k
            Corpus::Keep => 0,
43
0
            Corpus::Reject => -1,
44
        }
45
24.6k
    }
46
}
47
48
extern "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"]
59
24.6k
pub unsafe fn test_input_wrap(data: *const u8, size: usize) -> i32 {
60
24.6k
    let test_input = ::std::panic::catch_unwind(|| {
61
24.6k
        let data_slice = ::std::slice::from_raw_parts(data, size);
62
24.6k
        rust_fuzzer_test_input(data_slice)
63
24.6k
    });
64
24.6k
65
24.6k
    match test_input {
66
24.6k
        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
0
            ::std::process::abort();
71
        }
72
    }
73
24.6k
}
74
75
#[doc(hidden)]
76
24.6k
pub fn rust_libfuzzer_debug_path() -> &'static Option<String> {
77
    static RUST_LIBFUZZER_DEBUG_PATH: OnceLock<Option<String>> = OnceLock::new();
78
24.6k
    RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok())
79
24.6k
}
80
81
#[doc(hidden)]
82
20
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
83
20
    // Registers a panic hook that aborts the process before unwinding.
84
20
    // It is useful to abort before unwinding so that the fuzzer will then be
85
20
    // able to analyse the process stack frames to tell different bugs appart.
86
20
    //
87
20
    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
88
20
    // impossible to build code using compiler plugins with this flag.
89
20
    // We will be able to remove this code when
90
20
    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
91
20
    let default_hook = std::panic::take_hook();
92
20
    std::panic::set_hook(Box::new(move |panic_info| {
93
0
        default_hook(panic_info);
94
0
        std::process::abort();
95
20
    }));
96
20
    0
97
20
}
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]
226
macro_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
2
            pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
253
2
                $crate::initialize(_argc, _argv);
254
2
255
2
                // Supplied init code
256
2
                $init;
257
2
                0
258
2
            }
259
260
            #[no_mangle]
261
1.40k
            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
1.40k
                if let Some(path) = $crate::rust_libfuzzer_debug_path() {
268
                    use std::io::Write;
269
0
                    let mut file = std::fs::File::create(path)
270
0
                        .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
271
0
                    writeln!(&mut file, "{:?}", bytes)
272
0
                        .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
273
0
                    return 0;
274
1.40k
                }
275
1.40k
276
1.40k
                let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(bytes));
277
1.40k
                result.to_libfuzzer_code()
278
1.40k
            }
279
1.40k
280
1.40k
            // Split out the actual fuzzer into a separate function which is
281
1.40k
            // tagged as never being inlined. This ensures that if the fuzzer
282
1.40k
            // panics there's at least one stack frame which is named uniquely
283
1.40k
            // according to this specific fuzzer that this is embedded within.
284
1.40k
            //
285
1.40k
            // Systems like oss-fuzz try to deduplicate crashes and without this
286
1.40k
            // panics in separate fuzzers can accidentally appear the same
287
1.40k
            // because each fuzzer will have a function called
288
1.40k
            // `rust_fuzzer_test_input`. By using a normal Rust function here
289
1.40k
            // it's named something like `the_fuzzer_name::_::__libfuzzer_sys_run` which should
290
1.40k
            // ideally help prevent oss-fuzz from deduplicate fuzz bugs across
291
1.40k
            // distinct targets accidentally.
292
1.40k
            #[inline(never)]
293
1.71k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
22.9k
                $body
295
22.9k
            }
fuzzer_script_webp::_::__libfuzzer_sys_run
Line
Count
Source
293
1.40k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
1.40k
                $body
295
1.40k
            }
fuzzer_script_tiff::_::__libfuzzer_sys_run
Line
Count
Source
293
1.69k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
1.69k
                $body
295
1.69k
            }
fuzzer_script_bmp::_::__libfuzzer_sys_run
Line
Count
Source
293
1.81k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
1.81k
                $body
295
1.81k
            }
roundtrip_webp::_::__libfuzzer_sys_run
Line
Count
Source
293
1.71k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
                $body
295
            }
fuzzer_script_gif::_::__libfuzzer_sys_run
Line
Count
Source
293
1.84k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
1.84k
                $body
295
1.84k
            }
fuzzer_script_hdr::_::__libfuzzer_sys_run
Line
Count
Source
293
3.08k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
3.08k
                $body
295
3.08k
            }
fuzzer_script_ico::_::__libfuzzer_sys_run
Line
Count
Source
293
6.91k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
6.91k
                $body
295
6.91k
            }
Unexecuted instantiation: fuzzer_script_jpeg::_::__libfuzzer_sys_run
fuzzer_script_pnm::_::__libfuzzer_sys_run
Line
Count
Source
293
2.75k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
2.75k
                $body
295
2.75k
            }
fuzzer_script_png::_::__libfuzzer_sys_run
Line
Count
Source
293
2.92k
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
2.92k
                $body
295
2.92k
            }
Unexecuted instantiation: fuzzer_script_guess::_::__libfuzzer_sys_run
Unexecuted instantiation: fuzzer_script_exr::_::__libfuzzer_sys_run
fuzzer_script_tga::_::__libfuzzer_sys_run
Line
Count
Source
293
526
            fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty {
294
526
                $body
295
526
            }
296
1.71k
        };
297
1.71k
    };
298
1.71k
299
1.71k
    (|$data:ident: $dty:ty| $body:expr) => {
300
1.71k
        $crate::fuzz_target!(init: (), |$data: $dty| -> () { $body });
301
1.71k
    };
302
1.71k
303
1.71k
    (|$data:ident: $dty:ty| -> $rty:ty $body:block) => {
304
1.71k
        $crate::fuzz_target!(init: (), |$data: $dty| -> $rty { $body });
305
1.71k
    };
306
1.71k
307
1.71k
    (init: $init:expr, |$data:ident: $dty:ty| $body:expr) => {
308
1.71k
        $crate::fuzz_target!(init: $init, |$data: $dty| -> () { $body });
309
1.71k
    };
310
1.71k
311
1.71k
    (init: $init:expr, |$data:ident: $dty:ty| -> $rty:ty $body:block) => {
312
1.71k
        const _: () = {
313
1.71k
            /// Auto-generated functions
314
1.71k
            /// LLVMFuzzerInitialize is called once before the fuzzer starts.
315
1.71k
            #[no_mangle]
316
1.71k
            pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
317
1.71k
                $crate::initialize(_argc, _argv);
318
1.71k
319
1.71k
                // Supplied init code
320
1.71k
                $init;
321
1.71k
                0
322
1.71k
            }
323
1.71k
324
1.71k
            #[no_mangle]
325
1.71k
            pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
326
1.71k
                use $crate::arbitrary::{Arbitrary, Unstructured};
327
1.71k
328
1.71k
                // Early exit if we don't have enough bytes for the `Arbitrary`
329
1.71k
                // implementation. This helps the fuzzer avoid exploring all the
330
1.71k
                // different not-enough-input-bytes paths inside the `Arbitrary`
331
1.71k
                // implementation. Additionally, it exits faster, letting the fuzzer
332
1.71k
                // get to longer inputs that actually lead to interesting executions
333
1.71k
                // quicker.
334
1.71k
                if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
335
1.71k
                    return -1;
336
1.71k
                }
337
1.71k
338
1.71k
                let mut u = Unstructured::new(bytes);
339
1.71k
                let data = <$dty as Arbitrary>::arbitrary_take_rest(u);
340
1.71k
341
1.71k
                // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
342
1.71k
                // formatting of the input to that file. This is only intended for
343
1.71k
                // `cargo fuzz`'s use!
344
1.71k
345
1.71k
                // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
346
1.71k
                if let Some(path) = $crate::rust_libfuzzer_debug_path() {
347
1.71k
                    use std::io::Write;
348
1.71k
                    let mut file = std::fs::File::create(path)
349
1.71k
                        .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
350
1.71k
                    (match data {
351
1.71k
                        Ok(data) => writeln!(&mut file, "{:#?}", data),
352
1.71k
                        Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
353
1.71k
                    })
354
1.71k
                    .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
355
1.71k
                    return -1;
356
1.71k
                }
357
1.71k
358
1.71k
                let data = match data {
359
1.71k
                    Ok(d) => d,
360
1.71k
                    Err(_) => return -1,
361
1.71k
                };
362
1.71k
363
1.71k
                let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(data));
364
1.71k
                result.to_libfuzzer_code()
365
1.71k
            }
366
1.71k
            // See above for why this is split to a separate function.
367
1.71k
            #[inline(never)]
368
1.71k
            fn __libfuzzer_sys_run($data: $dty) -> $rty {
369
1.71k
                $body
370
1.71k
            }
371
1.71k
        };
372
1.71k
    };
373
1.71k
}
374
1.71k
375
1.71k
/// Define a custom mutator.
376
1.71k
///
377
1.71k
/// This is optional, and libFuzzer will use its own, default mutation strategy
378
1.71k
/// if this is not provided.
379
1.71k
///
380
1.71k
/// You might consider using a custom mutator when your fuzz target is very
381
1.71k
/// particular about the shape of its input:
382
1.71k
///
383
1.71k
/// * You want to fuzz "deeper" than just the parser.
384
1.71k
/// * The input contains checksums that have to match the hash of some subset of
385
1.71k
///   the data or else the whole thing is invalid, and therefore mutating any of
386
1.71k
///   that subset means you need to recompute the checksums.
387
1.71k
/// * Small random changes to the input buffer make it invalid.
388
1.71k
///
389
1.71k
/// That is, a custom mutator is useful in similar situations where [a `T:
390
1.71k
/// Arbitrary` input type](macro.fuzz_target.html#arbitrary-input-types) is
391
1.71k
/// useful. Note that the two approaches are not mutually exclusive; you can use
392
1.71k
/// whichever is easier for your problem domain or both!
393
1.71k
///
394
1.71k
/// ## Implementation Contract
395
1.71k
///
396
1.71k
/// The original, unmodified input is given in `data[..size]`.
397
1.71k
///
398
1.71k
/// You must modify the data in place and return the new size.
399
1.71k
///
400
1.71k
/// The new size should not be greater than `max_size`. If this is not the case,
401
1.71k
/// then the `data` will be truncated to fit within `max_size`. Note that
402
1.71k
/// `max_size < size` is possible when shrinking test cases.
403
1.71k
///
404
1.71k
/// You must produce the same mutation given the same `seed`. Generally, when
405
1.71k
/// choosing what kind of mutation to make or where to mutate, you should start
406
1.71k
/// by creating a random number generator (RNG) that is seeded with the given
407
1.71k
/// `seed` and then consult the RNG whenever making a decision:
408
1.71k
///
409
1.71k
/// ```no_run
410
1.71k
/// #![no_main]
411
1.71k
///
412
1.71k
/// use rand::{rngs::StdRng, Rng, SeedableRng};
413
1.71k
///
414
1.71k
/// libfuzzer_sys::fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| {
415
1.71k
///     let mut rng = StdRng::seed_from_u64(seed as u64);
416
1.71k
///
417
1.71k
/// #   let first_mutation = |_, _, _, _| todo!();
418
1.71k
/// #   let second_mutation = |_, _, _, _| todo!();
419
1.71k
/// #   let third_mutation = |_, _, _, _| todo!();
420
1.71k
/// #   let fourth_mutation = |_, _, _, _| todo!();
421
1.71k
///     // Choose which of our four supported kinds of mutations we want to make.
422
1.71k
///     match rng.gen_range(0..4) {
423
1.71k
///         0 => first_mutation(rng, data, size, max_size),
424
1.71k
///         1 => second_mutation(rng, data, size, max_size),
425
1.71k
///         2 => third_mutation(rng, data, size, max_size),
426
1.71k
///         3 => fourth_mutation(rng, data, size, max_size),
427
1.71k
///         _ => unreachable!()
428
1.71k
///     }
429
1.71k
/// });
430
1.71k
/// ```
431
1.71k
///
432
1.71k
/// ## Example: Compression
433
1.71k
///
434
1.71k
/// Consider a simple fuzz target that takes compressed data as input,
435
1.71k
/// decompresses it, and then asserts that the decompressed data doesn't begin
436
1.71k
/// with "boom". It is difficult for `libFuzzer` (or any other fuzzer) to crash
437
1.71k
/// this fuzz target because nearly all mutations it makes will invalidate the
438
1.71k
/// compression format. Therefore, we use a custom mutator that decompresses the
439
1.71k
/// raw input, mutates the decompressed data, and then recompresses it. This
440
1.71k
/// allows `libFuzzer` to quickly discover crashing inputs.
441
1.71k
///
442
1.71k
/// ```no_run
443
1.71k
/// #![no_main]
444
1.71k
///
445
1.71k
/// use flate2::{read::GzDecoder, write::GzEncoder, Compression};
446
1.71k
/// use libfuzzer_sys::{fuzz_mutator, fuzz_target};
447
1.71k
/// use std::io::{Read, Write};
448
1.71k
///
449
1.71k
/// fuzz_target!(|data: &[u8]| {
450
1.71k
///     // Decompress the input data and crash if it starts with "boom".
451
1.71k
///     if let Some(data) = decompress(data) {
452
1.71k
///         if data.starts_with(b"boom") {
453
1.71k
///             panic!();
454
1.71k
///         }
455
1.71k
///     }
456
1.71k
/// });
457
1.71k
///
458
1.71k
/// fuzz_mutator!(
459
1.71k
///     |data: &mut [u8], size: usize, max_size: usize, _seed: u32| {
460
1.71k
///         // Decompress the input data. If that fails, use a dummy value.
461
1.71k
///         let mut decompressed = decompress(&data[..size]).unwrap_or_else(|| b"hi".to_vec());
462
1.71k
///
463
1.71k
///         // Mutate the decompressed data with `libFuzzer`'s default mutator. Make
464
1.71k
///         // the `decompressed` vec's extra capacity available for insertion
465
1.71k
///         // mutations via `resize`.
466
1.71k
///         let len = decompressed.len();
467
1.71k
///         let cap = decompressed.capacity();
468
1.71k
///         decompressed.resize(cap, 0);
469
1.71k
///         let new_decompressed_size = libfuzzer_sys::fuzzer_mutate(&mut decompressed, len, cap);
470
1.71k
///
471
1.71k
///         // Recompress the mutated data.
472
1.71k
///         let compressed = compress(&decompressed[..new_decompressed_size]);
473
1.71k
///
474
1.71k
///         // Copy the recompressed mutated data into `data` and return the new size.
475
1.71k
///         let new_size = std::cmp::min(max_size, compressed.len());
476
1.71k
///         data[..new_size].copy_from_slice(&compressed[..new_size]);
477
1.71k
///         new_size
478
1.71k
///     }
479
1.71k
/// );
480
1.71k
///
481
1.71k
/// fn decompress(compressed_data: &[u8]) -> Option<Vec<u8>> {
482
1.71k
///     let mut decoder = GzDecoder::new(compressed_data);
483
1.71k
///     let mut decompressed = Vec::new();
484
1.71k
///     if decoder.read_to_end(&mut decompressed).is_ok() {
485
1.71k
///         Some(decompressed)
486
1.71k
///     } else {
487
1.71k
///         None
488
1.71k
///     }
489
1.71k
/// }
490
1.71k
///
491
1.71k
/// fn compress(data: &[u8]) -> Vec<u8> {
492
1.71k
///     let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
493
1.71k
///     encoder
494
1.71k
///         .write_all(data)
495
1.71k
///         .expect("writing into a vec is infallible");
496
1.71k
///     encoder.finish().expect("writing into a vec is infallible")
497
1.71k
/// }
498
1.71k
/// ```
499
1.71k
///
500
1.71k
/// This example is inspired by [a similar example from the official `libFuzzer`
501
1.71k
/// docs](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#example-compression).
502
1.71k
///
503
1.71k
/// ## More Example Ideas
504
1.71k
///
505
1.71k
/// * A PNG custom mutator that decodes a PNG, mutates the image, and then
506
1.71k
/// re-encodes the mutated image as a new PNG.
507
1.71k
///
508
1.71k
/// * A [`serde`](https://serde.rs/) custom mutator that deserializes your
509
1.71k
///   structure, mutates it, and then reserializes it.
510
1.71k
///
511
1.71k
/// * A Wasm binary custom mutator that inserts, replaces, and removes a
512
1.71k
///   bytecode instruction in a function's body.
513
1.71k
///
514
1.71k
/// * An HTTP request custom mutator that inserts, replaces, and removes a
515
1.71k
///   header from an HTTP request.
516
1.71k
#[macro_export]
517
1.71k
macro_rules! fuzz_mutator {
518
1.71k
    (
519
1.71k
        |
520
1.71k
        $data:ident : &mut [u8] ,
521
1.71k
        $size:ident : usize ,
522
1.71k
        $max_size:ident : usize ,
523
1.71k
        $seed:ident : u32 $(,)*
524
1.71k
        |
525
1.71k
        $body:block
526
1.71k
    ) => {
527
1.71k
        /// Auto-generated function. Do not use; only for LibFuzzer's
528
1.71k
        /// consumption.
529
1.71k
        #[export_name = "LLVMFuzzerCustomMutator"]
530
1.71k
        #[doc(hidden)]
531
1.71k
        pub unsafe fn rust_fuzzer_custom_mutator(
532
1.71k
            $data: *mut u8,
533
1.71k
            $size: usize,
534
1.71k
            $max_size: usize,
535
1.71k
            $seed: std::os::raw::c_uint,
536
1.71k
        ) -> usize {
537
1.71k
            // Depending on if we are growing or shrinking the test case, `size`
538
1.71k
            // might be larger or smaller than `max_size`. The `data`'s capacity
539
1.71k
            // is the maximum of the two.
540
1.71k
            let len = std::cmp::max($max_size, $size);
541
1.71k
            let $data: &mut [u8] = std::slice::from_raw_parts_mut($data, len);
542
1.71k
543
1.71k
            // `unsigned int` is generally a `u32`, but not on all targets. Do
544
1.71k
            // an infallible (and potentially lossy, but that's okay because it
545
1.71k
            // preserves determinism) conversion.
546
1.71k
            let $seed = $seed as u32;
547
1.71k
548
1.71k
            // Define and invoke a new, safe function so that the body doesn't
549
1.71k
            // inherit `unsafe`.
550
1.71k
            fn custom_mutator(
551
1.71k
                $data: &mut [u8],
552
1.71k
                $size: usize,
553
1.71k
                $max_size: usize,
554
1.71k
                $seed: u32,
555
1.71k
            ) -> usize {
556
1.71k
                $body
557
1.71k
            }
558
1.71k
            let new_size = custom_mutator($data, $size, $max_size, $seed);
559
1.71k
560
1.71k
            // Truncate the new size if it is larger than the max.
561
1.71k
            std::cmp::min(new_size, $max_size)
562
1.71k
        }
563
1.71k
    };
564
1.71k
}
565
1.71k
566
1.71k
/// The default `libFuzzer` mutator.
567
1.71k
///
568
1.71k
/// You generally don't have to use this at all unless you're defining a
569
1.71k
/// custom mutator with [the `fuzz_mutator!` macro][crate::fuzz_mutator].
570
1.71k
///
571
1.71k
/// Mutates `data[..size]` in place such that the mutated data is no larger than
572
1.71k
/// `max_size` and returns the new size of the mutated data.
573
1.71k
///
574
1.71k
/// To only allow shrinking mutations, make `max_size < size`.
575
1.71k
///
576
1.71k
/// To additionally allow mutations that grow the size of the data, make
577
1.71k
/// `max_size > size`.
578
1.71k
///
579
1.71k
/// Both `size` and `max_size` must be less than or equal to `data.len()`.
580
1.71k
///
581
1.71k
/// # Example
582
1.71k
///
583
1.71k
/// ```no_run
584
1.71k
/// // Create some data in a buffer.
585
1.71k
/// let mut data = vec![0; 128];
586
1.71k
/// data[..b"hello".len()].copy_from_slice(b"hello");
587
1.71k
///
588
1.71k
/// // Ask `libFuzzer` to mutate the data. By setting `max_size` to our buffer's
589
1.71k
/// // full length, we are allowing `libFuzzer` to perform mutations that grow
590
1.71k
/// // the size of the data, such as insertions.
591
1.71k
/// let size = b"hello".len();
592
1.71k
/// let max_size = data.len();
593
1.71k
/// let new_size = libfuzzer_sys::fuzzer_mutate(&mut data, size, max_size);
594
1.71k
///
595
1.71k
/// // Get the mutated data out of the buffer.
596
1.71k
/// let mutated_data = &data[..new_size];
597
1.71k
/// ```
598
1.71k
pub fn fuzzer_mutate(data: &mut [u8], size: usize, max_size: usize) -> usize {
599
0
    assert!(size <= data.len());
600
0
    assert!(max_size <= data.len());
601
0
    let new_size = unsafe { LLVMFuzzerMutate(data.as_mut_ptr(), size, max_size) };
602
0
    assert!(new_size <= data.len());
603
0
    new_size
604
0
}
605
606
/// Define a custom cross-over function to combine test cases.
607
///
608
/// This is optional, and libFuzzer will use its own, default cross-over strategy
609
/// if this is not provided. (As of the time of writing, this default strategy
610
/// takes alternating byte sequences from the two test cases, to construct the
611
/// new one) (see `FuzzerCrossOver.cpp`)
612
///
613
/// This could potentially be useful if your input is, for instance, a
614
/// sequence of fixed sized, multi-byte values and the crossover could then
615
/// merge discrete values rather than joining parts of a value.
616
///
617
/// ## Implementation Contract
618
///
619
/// The original, read-only inputs are given in the full slices of `data1`, and
620
/// `data2` (as opposed to the, potentially, partial slice of `data` in
621
/// [the `fuzz_mutator!` macro][crate::fuzz_mutator]).
622
///
623
/// You must place the new input merged from the two existing inputs' data
624
/// into `out` and return the size of the relevant data written to that slice.
625
///
626
/// The deterministic requirements from [the `fuzz_mutator!` macro][crate::fuzz_mutator]
627
/// apply as well to the `seed` parameter
628
///
629
/// ## Example: Floating-Point Sum NaN
630
///
631
/// ```no_run
632
/// #![no_main]
633
///
634
/// use libfuzzer_sys::{fuzz_crossover, fuzz_mutator, fuzz_target, fuzzer_mutate};
635
/// use rand::{rngs::StdRng, Rng, SeedableRng};
636
/// use std::mem::size_of;
637
///
638
/// fuzz_target!(|data: &[u8]| {
639
///     let (_, floats, _) = unsafe { data.align_to::<f64>() };
640
///
641
///     let res = floats
642
///         .iter()
643
///         .fold(0.0, |a, b| if b.is_nan() { a } else { a + b });
644
///
645
///     assert!(
646
///         !res.is_nan(),
647
///         "The sum of the following floats resulted in a NaN: {floats:?}"
648
///     );
649
/// });
650
///
651
/// // Inject some ...potentially problematic values to make the example close
652
/// // more quickly.
653
/// fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| {
654
///     let mut gen = StdRng::seed_from_u64(seed.into());
655
///
656
///     let (_, floats, _) = unsafe { data[..size].align_to_mut::<f64>() };
657
///
658
///     let x = gen.gen_range(0..=1000);
659
///     if x == 0 && !floats.is_empty() {
660
///         floats[0] = f64::INFINITY;
661
///     } else if x == 1000 && floats.len() > 1 {
662
///         floats[1] = f64::NEG_INFINITY;
663
///     } else {
664
///         return fuzzer_mutate(data, size, max_size);
665
///     }
666
///
667
///     size
668
/// });
669
///
670
/// fuzz_crossover!(|data1: &[u8], data2: &[u8], out: &mut [u8], _seed: u32| {
671
///     // Decode each source to see how many floats we can pull with proper
672
///     // alignment, and destination as to how many will fit with proper alignment
673
///     //
674
///     // Keep track of the unaligned prefix to `out`, as we will need to remember
675
///     // that those bytes will remain prepended to the actual floats that we
676
///     // write into the out buffer.
677
///     let (out_pref, out_floats, _) = unsafe { out.align_to_mut::<f64>() };
678
///     let (_, d1_floats, _) = unsafe { data1.align_to::<f64>() };
679
///     let (_, d2_floats, _) = unsafe { data2.align_to::<f64>() };
680
///
681
///     // Put into the destination, floats first from data1 then from data2, ...if
682
///     // possible given the size of `out`
683
///     let mut i: usize = 0;
684
///     for float in d1_floats.iter().chain(d2_floats).take(out_floats.len()) {
685
///         out_floats[i] = *float;
686
///         i += 1;
687
///     }
688
///
689
///     // Now that we have written the true floats, report back to the fuzzing
690
///     // engine that we left the unaligned `out` prefix bytes at the beginning of
691
///     // `out` and also then the floats that we wrote into the aligned float
692
///     // section.
693
///     out_pref.len() * size_of::<u8>() + i * size_of::<f64>()
694
/// });
695
/// ```
696
///
697
/// This example is a minimized version of [Erik Rigtorp's floating point
698
/// summation fuzzing example][1]. A more detailed version of this experiment
699
/// can be found in the `example_crossover` directory.
700
///
701
/// [1]: https://rigtorp.se/fuzzing-floating-point-code/
702
#[macro_export]
703
macro_rules! fuzz_crossover {
704
    (
705
        |
706
        $data1:ident : &[u8] ,
707
        $data2:ident : &[u8] ,
708
        $out:ident : &mut [u8] ,
709
        $seed:ident : u32 $(,)*
710
        |
711
        $body:block
712
    ) => {
713
        /// Auto-generated function. Do not use; only for LibFuzzer's
714
        /// consumption.
715
        #[export_name = "LLVMFuzzerCustomCrossOver"]
716
        #[doc(hidden)]
717
        pub unsafe fn rust_fuzzer_custom_crossover(
718
            $data1: *const u8,
719
            size1: usize,
720
            $data2: *const u8,
721
            size2: usize,
722
            $out: *mut u8,
723
            max_out_size: usize,
724
            $seed: std::os::raw::c_uint,
725
        ) -> usize {
726
            let $data1: &[u8] = std::slice::from_raw_parts($data1, size1);
727
            let $data2: &[u8] = std::slice::from_raw_parts($data2, size2);
728
            let $out: &mut [u8] = std::slice::from_raw_parts_mut($out, max_out_size);
729
730
            // `unsigned int` is generally a `u32`, but not on all targets. Do
731
            // an infallible (and potentially lossy, but that's okay because it
732
            // preserves determinism) conversion.
733
            let $seed = $seed as u32;
734
735
            // Define and invoke a new, safe function so that the body doesn't
736
            // inherit `unsafe`.
737
            fn custom_crossover(
738
                $data1: &[u8],
739
                $data2: &[u8],
740
                $out: &mut [u8],
741
                $seed: u32,
742
            ) -> usize {
743
                $body
744
            }
745
746
            custom_crossover($data1, $data2, $out, $seed)
747
        }
748
    };
749
}