@@ -136,74 +136,101 @@ pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize
136
136
#[ macro_export]
137
137
macro_rules! fuzz_target {
138
138
( |$bytes: ident| $body: block) => {
139
- /// Auto-generated function
140
- #[ no_mangle]
141
- pub extern "C" fn rust_fuzzer_test_input( $bytes: & [ u8 ] ) {
142
- // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
143
- // formatting of the input to that file. This is only intended for
144
- // `cargo fuzz`'s use!
139
+ const _: ( ) = {
140
+ /// Auto-generated function
141
+ #[ no_mangle]
142
+ pub extern "C" fn rust_fuzzer_test_input( bytes: & [ u8 ] ) {
143
+ // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
144
+ // formatting of the input to that file. This is only intended for
145
+ // `cargo fuzz`'s use!
145
146
146
- // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
147
- if let Some ( path) = $crate:: RUST_LIBFUZZER_DEBUG_PATH . get( ) {
148
- use std:: io:: Write ;
149
- let mut file = std:: fs:: File :: create( path)
150
- . expect( "failed to create `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
151
- writeln!( & mut file, "{:?}" , $bytes)
152
- . expect( "failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
153
- return ;
147
+ // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
148
+ if let Some ( path) = $crate:: RUST_LIBFUZZER_DEBUG_PATH . get( ) {
149
+ use std:: io:: Write ;
150
+ let mut file = std:: fs:: File :: create( path)
151
+ . expect( "failed to create `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
152
+ writeln!( & mut file, "{:?}" , bytes)
153
+ . expect( "failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
154
+ return ;
155
+ }
156
+
157
+ run( bytes)
154
158
}
155
159
156
- $body
157
- }
160
+ // Split out the actual fuzzer into a separate function which is
161
+ // tagged as never being inlined. This ensures that if the fuzzer
162
+ // panics there's at least one stack frame which is named uniquely
163
+ // according to this specific fuzzer that this is embedded within.
164
+ //
165
+ // Systems like oss-fuzz try to deduplicate crashes and without this
166
+ // panics in separate fuzzers can accidentally appear the same
167
+ // because each fuzzer will have a function called
168
+ // `rust_fuzzer_test_input`. By using a normal Rust function here
169
+ // it's named something like `the_fuzzer_name::_::run` which should
170
+ // ideally help prevent oss-fuzz from deduplicate fuzz bugs across
171
+ // distinct targets accidentally.
172
+ #[ inline( never) ]
173
+ fn run( $bytes: & [ u8 ] ) {
174
+ $body
175
+ }
176
+ } ;
158
177
} ;
159
178
160
179
( |$data: ident: & [ u8 ] | $body: block) => {
161
180
$crate:: fuzz_target!( |$data| $body) ;
162
181
} ;
163
182
164
183
( |$data: ident: $dty: ty| $body: block) => {
165
- /// Auto-generated function
166
- #[ no_mangle]
167
- pub extern "C" fn rust_fuzzer_test_input( bytes: & [ u8 ] ) {
168
- use $crate:: arbitrary:: { Arbitrary , Unstructured } ;
184
+ const _: ( ) = {
185
+ /// Auto-generated function
186
+ #[ no_mangle]
187
+ pub extern "C" fn rust_fuzzer_test_input( bytes: & [ u8 ] ) {
188
+ use $crate:: arbitrary:: { Arbitrary , Unstructured } ;
169
189
170
- // Early exit if we don't have enough bytes for the `Arbitrary`
171
- // implementation. This helps the fuzzer avoid exploring all the
172
- // different not-enough-input-bytes paths inside the `Arbitrary`
173
- // implementation. Additionally, it exits faster, letting the fuzzer
174
- // get to longer inputs that actually lead to interesting executions
175
- // quicker.
176
- if bytes. len( ) < <$dty as Arbitrary >:: size_hint( 0 ) . 0 {
177
- return ;
178
- }
190
+ // Early exit if we don't have enough bytes for the `Arbitrary`
191
+ // implementation. This helps the fuzzer avoid exploring all the
192
+ // different not-enough-input-bytes paths inside the `Arbitrary`
193
+ // implementation. Additionally, it exits faster, letting the fuzzer
194
+ // get to longer inputs that actually lead to interesting executions
195
+ // quicker.
196
+ if bytes. len( ) < <$dty as Arbitrary >:: size_hint( 0 ) . 0 {
197
+ return ;
198
+ }
179
199
180
- let mut u = Unstructured :: new( bytes) ;
181
- let data = <$dty as Arbitrary >:: arbitrary_take_rest( u) ;
200
+ let mut u = Unstructured :: new( bytes) ;
201
+ let data = <$dty as Arbitrary >:: arbitrary_take_rest( u) ;
182
202
183
- // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
184
- // formatting of the input to that file. This is only intended for
185
- // `cargo fuzz`'s use!
203
+ // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
204
+ // formatting of the input to that file. This is only intended for
205
+ // `cargo fuzz`'s use!
186
206
187
- // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
188
- if let Some ( path) = $crate:: RUST_LIBFUZZER_DEBUG_PATH . get( ) {
189
- use std:: io:: Write ;
190
- let mut file = std:: fs:: File :: create( path)
191
- . expect( "failed to create `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
192
- ( match data {
193
- Ok ( data) => writeln!( & mut file, "{:#?}" , data) ,
194
- Err ( err) => writeln!( & mut file, "Arbitrary Error: {}" , err) ,
195
- } )
196
- . expect( "failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
197
- return ;
198
- }
207
+ // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
208
+ if let Some ( path) = $crate:: RUST_LIBFUZZER_DEBUG_PATH . get( ) {
209
+ use std:: io:: Write ;
210
+ let mut file = std:: fs:: File :: create( path)
211
+ . expect( "failed to create `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
212
+ ( match data {
213
+ Ok ( data) => writeln!( & mut file, "{:#?}" , data) ,
214
+ Err ( err) => writeln!( & mut file, "Arbitrary Error: {}" , err) ,
215
+ } )
216
+ . expect( "failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file" ) ;
217
+ return ;
218
+ }
199
219
200
- let $ data = match data {
201
- Ok ( d) => d,
202
- Err ( _) => return ,
203
- } ;
220
+ let data = match data {
221
+ Ok ( d) => d,
222
+ Err ( _) => return ,
223
+ } ;
204
224
205
- $body
206
- }
225
+ run( data)
226
+ }
227
+
228
+ // See above for why this is split to a separate function.
229
+ #[ inline( never) ]
230
+ fn run( $data: $dty) {
231
+ $body
232
+ }
233
+ } ;
207
234
} ;
208
235
}
209
236
0 commit comments