/rust/git/checkouts/libfuzzer-sys-2a22126b2abe19d7/35ce7d7/src/lib.rs
Line  | Count  | Source  | 
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  | 16.4k  | pub fn test_input_wrap(data: *const u8, size: usize) -> i32 { | 
25  | 16.4k  |     let test_input = ::std::panic::catch_unwind(|| unsafe { | 
26  | 16.4k  |         let data_slice = ::std::slice::from_raw_parts(data, size);  | 
27  | 16.4k  |         rust_fuzzer_test_input(data_slice);  | 
28  | 16.4k  |     });  | 
29  | 16.4k  |     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  | 16.4k  |     }  | 
34  | 16.4k  |     0  | 
35  | 16.4k  | }  | 
36  |  |  | 
37  |  | #[doc(hidden)]  | 
38  |  | #[export_name = "LLVMFuzzerInitialize"]  | 
39  | 8  | pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize { | 
40  |  |     // Registers a panic hook that aborts the process before unwinding.  | 
41  |  |     // It is useful to abort before unwinding so that the fuzzer will then be  | 
42  |  |     // able to analyse the process stack frames to tell different bugs appart.  | 
43  |  |     //  | 
44  |  |     // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently  | 
45  |  |     // impossible to build code using compiler plugins with this flag.  | 
46  |  |     // We will be able to remove this code when  | 
47  |  |     // https://github.com/rust-lang/cargo/issues/5423 is fixed.  | 
48  | 8  |     let default_hook = ::std::panic::take_hook();  | 
49  | 8  |     ::std::panic::set_hook(Box::new(move |panic_info| { | 
50  | 0  |         default_hook(panic_info);  | 
51  | 0  |         ::std::process::abort();  | 
52  |  |     }));  | 
53  | 8  |     0  | 
54  | 8  | }  | 
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  | 2.99k  |         pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) { | 
121  |  |             $body  | 
122  | 2.99k  |         }  | 
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  |  |         pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) { | 
132  |  |             use libfuzzer_sys::arbitrary::{Arbitrary, RingBuffer}; | 
133  |  |  | 
134  |  |             let mut buf = match RingBuffer::new(bytes, bytes.len()) { | 
135  |  |                 Ok(b) => b,  | 
136  |  |                 Err(_) => return,  | 
137  |  |             };  | 
138  |  |  | 
139  |  |             let $data: $dty = match Arbitrary::arbitrary(&mut buf) { | 
140  |  |                 Ok(d) => d,  | 
141  |  |                 Err(_) => return,  | 
142  |  |             };  | 
143  |  |  | 
144  |  |             $body  | 
145  |  |         }  | 
146  |  |     };  | 
147  |  | }  |