19
19
20
20
#include < atomic>
21
21
#include < chrono>
22
+ #include < condition_variable>
22
23
#include < fstream>
23
24
#include < memory>
24
25
#include < mutex>
@@ -68,6 +69,9 @@ struct FuzzJob {
68
69
std::string LogPath;
69
70
std::string SeedListPath;
70
71
std::string CFPath;
72
+ size_t JobId;
73
+
74
+ int DftTimeInSeconds = 0 ;
71
75
72
76
// Fuzzing Outputs.
73
77
int ExitCode;
@@ -102,6 +106,8 @@ struct GlobalEnv {
102
106
103
107
size_t NumRuns = 0 ;
104
108
109
+ std::string StopFile () { return DirPlusFile (TempDir, " STOP" ); }
110
+
105
111
size_t secondsSinceProcessStartUp () const {
106
112
return std::chrono::duration_cast<std::chrono::seconds>(
107
113
std::chrono::system_clock::now () - ProcessStartTime)
@@ -119,6 +125,7 @@ struct GlobalEnv {
119
125
Cmd.addFlag (" print_final_stats" , " 1" );
120
126
Cmd.addFlag (" print_funcs" , " 0" ); // no need to spend time symbolizing.
121
127
Cmd.addFlag (" max_total_time" , std::to_string (std::min ((size_t )300 , JobId)));
128
+ Cmd.addFlag (" stop_file" , StopFile ());
122
129
if (!DataFlowBinary.empty ()) {
123
130
Cmd.addFlag (" data_flow_trace" , DFTDir);
124
131
if (!Cmd.hasFlag (" focus_function" ))
@@ -128,11 +135,14 @@ struct GlobalEnv {
128
135
std::string Seeds;
129
136
if (size_t CorpusSubsetSize =
130
137
std::min (Files.size (), (size_t )sqrt (Files.size () + 2 ))) {
138
+ auto Time1 = std::chrono::system_clock::now ();
131
139
for (size_t i = 0 ; i < CorpusSubsetSize; i++) {
132
140
auto &SF = Files[Rand->SkewTowardsLast (Files.size ())];
133
141
Seeds += (Seeds.empty () ? " " : " ," ) + SF;
134
142
CollectDFT (SF);
135
143
}
144
+ auto Time2 = std::chrono::system_clock::now ();
145
+ Job->DftTimeInSeconds = duration_cast<seconds>(Time2 - Time1).count ();
136
146
}
137
147
if (!Seeds.empty ()) {
138
148
Job->SeedListPath =
@@ -144,6 +154,7 @@ struct GlobalEnv {
144
154
Job->CorpusDir = DirPlusFile (TempDir, " C" + std::to_string (JobId));
145
155
Job->FeaturesDir = DirPlusFile (TempDir, " F" + std::to_string (JobId));
146
156
Job->CFPath = DirPlusFile (TempDir, std::to_string (JobId) + " .merge" );
157
+ Job->JobId = JobId;
147
158
148
159
149
160
Cmd.addArgument (Job->CorpusDir );
@@ -189,6 +200,13 @@ struct GlobalEnv {
189
200
}
190
201
}
191
202
}
203
+ // if (!FilesToAdd.empty() || Job->ExitCode != 0)
204
+ Printf (" #%zd: cov: %zd ft: %zd corp: %zd exec/s %zd "
205
+ " oom/timeout/crash: %zd/%zd/%zd time: %zds job: %zd dft_time: %d\n " ,
206
+ NumRuns, Cov.size (), Features.size (), Files.size (),
207
+ Stats.average_exec_per_sec , NumOOMs, NumTimeouts, NumCrashes,
208
+ secondsSinceProcessStartUp (), Job->JobId , Job->DftTimeInSeconds );
209
+
192
210
if (MergeCandidates.empty ()) return ;
193
211
194
212
Vector<std::string> FilesToAdd;
@@ -209,12 +227,6 @@ struct GlobalEnv {
209
227
PrintPC (" NEW_FUNC: %p %F %L\n " , " " ,
210
228
TPC.GetNextInstructionPc (TE->PC ));
211
229
212
- if (!FilesToAdd.empty () || Job->ExitCode != 0 )
213
- Printf (" #%zd: cov: %zd ft: %zd corp: %zd exec/s %zd "
214
- " oom/timeout/crash: %zd/%zd/%zd time: %zds\n " , NumRuns,
215
- Cov.size (), Features.size (), Files.size (),
216
- Stats.average_exec_per_sec ,
217
- NumOOMs, NumTimeouts, NumCrashes, secondsSinceProcessStartUp ());
218
230
}
219
231
220
232
@@ -239,28 +251,29 @@ struct GlobalEnv {
239
251
struct JobQueue {
240
252
std::queue<FuzzJob *> Qu;
241
253
std::mutex Mu;
254
+ std::condition_variable Cv;
242
255
243
256
void Push (FuzzJob *Job) {
244
- std::lock_guard<std::mutex> Lock (Mu);
245
- Qu.push (Job);
257
+ {
258
+ std::lock_guard<std::mutex> Lock (Mu);
259
+ Qu.push (Job);
260
+ }
261
+ Cv.notify_one ();
246
262
}
247
263
FuzzJob *Pop () {
248
- std::lock_guard<std::mutex> Lock (Mu);
249
- if (Qu.empty ()) return nullptr ;
264
+ std::unique_lock<std::mutex> Lk (Mu);
265
+ // std::lock_guard<std::mutex> Lock(Mu);
266
+ Cv.wait (Lk, [&]{return !Qu.empty ();});
267
+ assert (!Qu.empty ());
250
268
auto Job = Qu.front ();
251
269
Qu.pop ();
252
270
return Job;
253
271
}
254
272
};
255
273
256
- void WorkerThread (std::atomic<bool > *Stop, JobQueue *FuzzQ, JobQueue *MergeQ) {
257
- while (!Stop->load ()) {
258
- auto Job = FuzzQ->Pop ();
274
+ void WorkerThread (JobQueue *FuzzQ, JobQueue *MergeQ) {
275
+ while (auto Job = FuzzQ->Pop ()) {
259
276
// Printf("WorkerThread: job %p\n", Job);
260
- if (!Job) {
261
- SleepSeconds (1 );
262
- continue ;
263
- }
264
277
Job->ExitCode = ExecuteCommand (Job->Cmd );
265
278
MergeQ->Push (Job);
266
279
}
@@ -307,27 +320,29 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
307
320
int ExitCode = 0 ;
308
321
309
322
JobQueue FuzzQ, MergeQ;
310
- std::atomic<bool > Stop (false );
323
+
324
+ auto StopJobs = [&]() {
325
+ for (int i = 0 ; i < NumJobs; i++)
326
+ FuzzQ.Push (nullptr );
327
+ MergeQ.Push (nullptr );
328
+ WriteToFile (Unit ({1 }), Env.StopFile ());
329
+ };
311
330
312
331
size_t JobId = 1 ;
313
332
Vector<std::thread> Threads;
314
333
for (int t = 0 ; t < NumJobs; t++) {
315
- Threads.push_back (std::thread (WorkerThread, &Stop, & FuzzQ, &MergeQ));
334
+ Threads.push_back (std::thread (WorkerThread, &FuzzQ, &MergeQ));
316
335
FuzzQ.Push (Env.CreateNewJob (JobId++));
317
336
}
318
337
319
338
while (true ) {
320
339
std::unique_ptr<FuzzJob> Job (MergeQ.Pop ());
321
- if (!Job) {
322
- if (Stop)
323
- break ;
324
- SleepSeconds (1 );
325
- continue ;
326
- }
340
+ if (!Job)
341
+ break ;
327
342
ExitCode = Job->ExitCode ;
328
343
if (ExitCode == Options.InterruptExitCode ) {
329
344
Printf (" ==%lu== libFuzzer: a child was interrupted; exiting\n " , GetPid ());
330
- Stop = true ;
345
+ StopJobs () ;
331
346
break ;
332
347
}
333
348
Fuzzer::MaybeExitGracefully ();
@@ -352,30 +367,31 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
352
367
// And exit if we don't ignore this crash.
353
368
Printf (" INFO: log from the inner process:\n %s" ,
354
369
FileToString (Job->LogPath ).c_str ());
355
- Stop = true ;
370
+ StopJobs ();
371
+ break ;
356
372
}
357
373
}
358
374
359
375
// Stop if we are over the time budget.
360
376
// This is not precise, since other threads are still running
361
377
// and we will wait while joining them.
362
378
// We also don't stop instantly: other jobs need to finish.
363
- if (Options.MaxTotalTimeSec > 0 && !Stop &&
379
+ if (Options.MaxTotalTimeSec > 0 &&
364
380
Env.secondsSinceProcessStartUp () >= (size_t )Options.MaxTotalTimeSec ) {
365
381
Printf (" INFO: fuzzed for %zd seconds, wrapping up soon\n " ,
366
382
Env.secondsSinceProcessStartUp ());
367
- Stop = true ;
383
+ StopJobs ();
384
+ break ;
368
385
}
369
- if (!Stop && Env.NumRuns >= Options.MaxNumberOfRuns ) {
386
+ if (Env.NumRuns >= Options.MaxNumberOfRuns ) {
370
387
Printf (" INFO: fuzzed for %zd iterations, wrapping up soon\n " ,
371
388
Env.NumRuns );
372
- Stop = true ;
389
+ StopJobs ();
390
+ break ;
373
391
}
374
392
375
- if (!Stop)
376
- FuzzQ.Push (Env.CreateNewJob (JobId++));
393
+ FuzzQ.Push (Env.CreateNewJob (JobId++));
377
394
}
378
- Stop = true ;
379
395
380
396
for (auto &T : Threads)
381
397
T.join ();
0 commit comments