Coverage Report

Created: 2025-07-01 07:43

/rust/git/checkouts/libfuzzer-sys-e07fde05820d7bc6/35ce7d7/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
16
extern "C" {
17
    // We do not actually cross the FFI bound here.
18
    #[allow(improper_ctypes)]
19
    fn rust_fuzzer_test_input(input: &[u8]);
20
}
21
22
#[doc(hidden)]
23
#[export_name = "LLVMFuzzerTestOneInput"]
24
0
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
25
0
    let test_input = ::std::panic::catch_unwind(|| unsafe {
26
0
        let data_slice = ::std::slice::from_raw_parts(data, size);
27
0
        rust_fuzzer_test_input(data_slice);
28
0
    });
29
0
    if test_input.err().is_some() {
30
        // hopefully the custom panic hook will be called before and abort the
31
        // process before the stack frames are unwinded.
32
0
        ::std::process::abort();
33
0
    }
34
0
    0
35
0
}
36
37
#[doc(hidden)]
38
#[export_name = "LLVMFuzzerInitialize"]
39
2
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
40
2
    // Registers a panic hook that aborts the process before unwinding.
41
2
    // It is useful to abort before unwinding so that the fuzzer will then be
42
2
    // able to analyse the process stack frames to tell different bugs appart.
43
2
    //
44
2
    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
45
2
    // impossible to build code using compiler plugins with this flag.
46
2
    // We will be able to remove this code when
47
2
    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
48
2
    let default_hook = ::std::panic::take_hook();
49
2
    ::std::panic::set_hook(Box::new(move |panic_info| {
50
0
        default_hook(panic_info);
51
0
        ::std::process::abort();
52
2
    }));
53
2
    0
54
2
}
55
56
/// Define a fuzz target.
57
///
58
/// ## Example
59
///
60
/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
61
/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
62
///
63
/// ```no_run
64
/// #![no_main]
65
///
66
/// use libfuzzer_sys::fuzz_target;
67
///
68
/// // Note: `|input|` is short for `|input: &[u8]|`.
69
/// fuzz_target!(|input| {
70
///     let _result: Result<_, _> = my_crate::parse(input);
71
/// });
72
/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
73
/// ```
74
///
75
/// ## Arbitrary Input Types
76
///
77
/// The input is a `&[u8]` slice by default, but you can take arbitrary input
78
/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
79
/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
80
/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
81
///
82
/// For example, if you wanted to take an arbitrary RGB color, you could do the
83
/// following:
84
///
85
/// ```no_run
86
/// #![no_main]
87
///
88
/// use libfuzzer_sys::{arbitrary::{Arbitrary, Unstructured}, fuzz_target};
89
///
90
/// #[derive(Debug)]
91
/// pub struct Rgb {
92
///     r: u8,
93
///     g: u8,
94
///     b: u8,
95
/// }
96
///
97
/// impl Arbitrary for Rgb {
98
///     fn arbitrary<U>(raw: &mut U) -> Result<Self, U::Error>
99
///     where
100
///         U: Unstructured + ?Sized
101
///     {
102
///         let mut buf = [0; 3];
103
///         raw.fill_buffer(&mut buf)?;
104
///         let r = buf[0];
105
///         let g = buf[1];
106
///         let b = buf[2];
107
///         Ok(Rgb { r, g, b })
108
///     }
109
/// }
110
///
111
/// // Write a fuzz target that works with RGB colors instead of raw bytes.
112
/// fuzz_target!(|color: Rgb| {
113
///     my_crate::convert_color(color);
114
/// });
115
/// # mod my_crate { fn convert_color(_: super::Rgb) {} }
116
#[macro_export]
117
macro_rules! fuzz_target {
118
    (|$bytes:ident| $body:block) => {
119
        #[no_mangle]
120
        pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
121
            $body
122
        }
123
    };
124
125
    (|$data:ident: &[u8]| $body:block) => {
126
        fuzz_target!(|$data| $body);
127
    };
128
129
    (|$data:ident: $dty: ty| $body:block) => {
130
        #[no_mangle]
131
0
        pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
132
            use libfuzzer_sys::arbitrary::{Arbitrary, RingBuffer};
133
134
0
            let mut buf = match RingBuffer::new(bytes, bytes.len()) {
135
0
                Ok(b) => b,
136
0
                Err(_) => return,
137
            };
138
139
0
            let $data: $dty = match Arbitrary::arbitrary(&mut buf) {
140
0
                Ok(d) => d,
141
0
                Err(_) => return,
142
            };
143
144
            $body
145
        }
146
    };
147
}