15
15
*/
16
16
17
17
import path from "path" ;
18
+ import * as process from "process" ;
19
+ import * as tmp from "tmp" ;
20
+ import * as fs from "fs" ;
21
+
18
22
import * as fuzzer from "@jazzer.js/fuzzer" ;
19
23
import * as hooking from "@jazzer.js/hooking" ;
20
- import { registerInstrumentor } from "@jazzer.js/instrumentor" ;
21
24
import { trackedHooks } from "@jazzer.js/hooking" ;
25
+ import {
26
+ registerInstrumentor ,
27
+ Instrumentor ,
28
+ FileSyncIdStrategy ,
29
+ MemorySyncIdStrategy ,
30
+ } from "@jazzer.js/instrumentor" ;
31
+
32
+ // Remove temporary files on exit
33
+ tmp . setGracefulCleanup ( ) ;
22
34
23
35
// libFuzzer uses exit code 77 in case of a crash, so use a similar one for
24
36
// failed error expectations.
@@ -38,6 +50,7 @@ export interface Options {
38
50
customHooks : string [ ] ;
39
51
expectedErrors : string [ ] ;
40
52
timeout ?: number ;
53
+ idSyncFile ?: string ;
41
54
}
42
55
43
56
interface FuzzModule {
@@ -54,7 +67,16 @@ export async function initFuzzing(options: Options) {
54
67
registerGlobals ( ) ;
55
68
await Promise . all ( options . customHooks . map ( importModule ) ) ;
56
69
if ( ! options . dryRun ) {
57
- registerInstrumentor ( options . includes , options . excludes ) ;
70
+ registerInstrumentor (
71
+ new Instrumentor (
72
+ options . includes ,
73
+ options . excludes ,
74
+
75
+ options . idSyncFile !== undefined
76
+ ? new FileSyncIdStrategy ( options . idSyncFile )
77
+ : new MemorySyncIdStrategy ( )
78
+ )
79
+ ) ;
58
80
}
59
81
}
60
82
@@ -90,6 +112,59 @@ export async function startFuzzingNoInit(
90
112
return Promise . resolve ( ) . then ( ( ) => fuzzerFn ( fuzzFn , fuzzerOptions ) ) ;
91
113
}
92
114
115
+ function prepareLibFuzzerArg0 ( fuzzerOptions : string [ ] ) : string {
116
+ // When we run in a libFuzzer mode that spawns subprocesses, we create a wrapper script
117
+ // that can be used as libFuzzer's argv[0]. In the fork mode, the main libFuzzer process
118
+ // uses argv[0] to spawn further processes that perform the actual fuzzing.
119
+ const libFuzzerSpawnsProcess = fuzzerOptions . some (
120
+ ( flag ) =>
121
+ flag . startsWith ( "-fork=" ) ||
122
+ flag . startsWith ( "-jobs=" ) ||
123
+ flag . startsWith ( "-merge=" )
124
+ ) ;
125
+
126
+ if ( ! libFuzzerSpawnsProcess ) {
127
+ // Return a fake argv[0] to start the fuzzer if libFuzzer does not spawn new processes.
128
+ return "unused_arg0_report_a_bug_if_you_see_this" ;
129
+ } else {
130
+ // Create a wrapper script and return its path.
131
+ return createWrapperScript ( fuzzerOptions ) ;
132
+ }
133
+ }
134
+
135
+ function createWrapperScript ( fuzzerOptions : string [ ] ) {
136
+ const jazzerArgs = process . argv . filter (
137
+ ( arg ) => arg !== "--" && fuzzerOptions . indexOf ( arg ) === - 1
138
+ ) ;
139
+
140
+ if ( jazzerArgs . indexOf ( "--id_sync_file" ) === - 1 ) {
141
+ const idSyncFile = tmp . fileSync ( {
142
+ mode : 0o600 ,
143
+ prefix : "jazzer.js" ,
144
+ postfix : "idSync" ,
145
+ } ) ;
146
+ jazzerArgs . push ( "--id_sync_file" , idSyncFile . name ) ;
147
+ fs . closeSync ( idSyncFile . fd ) ;
148
+ }
149
+
150
+ const isWindows = process . platform === "win32" ;
151
+
152
+ const scriptContent = `${ isWindows ? "@echo off" : "#!/usr/bin/env sh" }
153
+ cd "${ process . cwd ( ) } "
154
+ ${ jazzerArgs . map ( ( s ) => '"' + s + '"' ) . join ( " " ) } -- ${ isWindows ? "%*" : "$@" }
155
+ ` ;
156
+
157
+ const scriptTempFile = tmp . fileSync ( {
158
+ mode : 0o700 ,
159
+ prefix : "jazzer.js" ,
160
+ postfix : "libfuzzer" + ( isWindows ? ".bat" : ".sh" ) ,
161
+ } ) ;
162
+ fs . writeFileSync ( scriptTempFile . name , scriptContent ) ;
163
+ fs . closeSync ( scriptTempFile . fd ) ;
164
+
165
+ return scriptTempFile . name ;
166
+ }
167
+
93
168
function stopFuzzing ( err : unknown , expectedErrors : string [ ] ) {
94
169
if ( process . env . JAZZER_DEBUG ) {
95
170
trackedHooks . categorizeUnknown ( HookManager . hooks ) . print ( ) ;
@@ -183,7 +258,8 @@ function buildFuzzerOptions(options: Options): string[] {
183
258
const inSeconds = options . timeout / 1000 ;
184
259
opts = opts . concat ( `-timeout=${ inSeconds } ` ) ;
185
260
}
186
- return opts ;
261
+
262
+ return [ prepareLibFuzzerArg0 ( opts ) , ...opts ] ;
187
263
}
188
264
189
265
async function loadFuzzFunction ( options : Options ) : Promise < fuzzer . FuzzTarget > {
0 commit comments