Coverage Report

Created: 2024-12-17 06:15

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