@@ -104,12 +104,11 @@ def process_afl_test_cases(cargs):
104
104
run_once = False
105
105
tot_files = 0
106
106
fuzz_dir = ''
107
+ curr_file = ''
107
108
108
109
afl_files = []
109
110
cov_paths = {}
110
111
111
- curr_file = ''
112
-
113
112
### main coverage tracking dictionary
114
113
cov = {}
115
114
cov ['zero' ] = {}
@@ -121,21 +120,25 @@ def process_afl_test_cases(cargs):
121
120
rv = False
122
121
break
123
122
124
- dir_ctr = 0
123
+ dir_ctr = 0
124
+ last_dir = False
125
125
126
126
do_coverage = True
127
127
if cargs .cover_corpus :
128
128
do_coverage = False
129
129
130
130
for fuzz_dir in cov_paths ['dirs' ]:
131
131
132
+ do_break = False
133
+ last_file = False
132
134
num_files = 0
133
135
new_files = []
134
136
tmp_files = import_test_cases (fuzz_dir + '/queue' )
135
137
dir_ctr += 1
138
+ f_ctr = 0
136
139
137
- if cargs . cover_corpus and dir_ctr == len (cov_paths ):
138
- do_coverage = True
140
+ if dir_ctr == len (cov_paths [ 'dirs' ] ):
141
+ last_dir = True
139
142
140
143
for f in tmp_files :
141
144
if f not in afl_files :
@@ -149,6 +152,15 @@ def process_afl_test_cases(cargs):
149
152
150
153
for f in new_files :
151
154
155
+ f_ctr += 1
156
+ if f_ctr == len (new_files ):
157
+ last_file = True
158
+
159
+ if cargs .cover_corpus and last_dir and last_file :
160
+ ### in --cover-corpus mode, only run lcov after all AFL
161
+ ### test cases have been processed
162
+ do_coverage = True
163
+
152
164
out_lines = []
153
165
curr_cycle = get_cycle_num (num_files , cargs )
154
166
@@ -169,16 +181,25 @@ def process_afl_test_cases(cargs):
169
181
cov_paths ['log_file' ], cargs , WANT_OUTPUT )[1 ]
170
182
run_once = True
171
183
172
- if do_coverage :
184
+ if cargs .afl_queue_id_limit \
185
+ and num_files >= cargs .afl_queue_id_limit - 1 :
186
+ logr ("[+] queue/ id limit of %d reached..." \
187
+ % cargs .afl_queue_id_limit ,
188
+ cov_paths ['log_file' ], cargs )
189
+ do_break = True
190
+ if cargs .cover_corpus and last_dir :
191
+ do_coverage = True
192
+
193
+ if do_coverage and not cargs .coverage_at_exit :
173
194
### generate the code coverage stats for this test case
174
- gen_coverage (cov_paths , cargs )
195
+ lcov_gen_coverage (cov_paths , cargs )
175
196
176
197
### diff to the previous code coverage, look for new
177
198
### lines/functions, and write out results
178
199
coverage_diff (curr_cycle , fuzz_dir , cov_paths , f ,
179
200
cov , cargs )
180
201
181
- if not cargs . disable_lcov_web and cargs .lcov_web_all :
202
+ if cargs .lcov_web_all :
182
203
gen_web_cov_report (fuzz_dir , cov_paths , cargs )
183
204
184
205
### log the output of the very first coverage command to
@@ -196,11 +217,7 @@ def process_afl_test_cases(cargs):
196
217
num_files += 1
197
218
tot_files += 1
198
219
199
- if cargs .afl_queue_id_limit \
200
- and num_files > cargs .afl_queue_id_limit :
201
- logr ("[+] queue/ id limit of %d reached..." \
202
- % cargs .afl_queue_id_limit ,
203
- cov_paths ['log_file' ], cargs )
220
+ if do_break :
204
221
break
205
222
206
223
if cargs .live :
@@ -223,12 +240,21 @@ def process_afl_test_cases(cargs):
223
240
% (tot_files , len (afl_files )),
224
241
cov_paths ['log_file' ], cargs )
225
242
243
+ if cargs .coverage_at_exit :
244
+ ### generate the code coverage stats for this test case
245
+ lcov_gen_coverage (cov_paths , cargs )
246
+
247
+ ### diff to the previous code coverage, look for new
248
+ ### lines/functions, and write out results
249
+ coverage_diff (curr_cycle , fuzz_dir , cov_paths ,
250
+ cov_paths ['id_file' ], cov , cargs )
251
+
226
252
### write out the final zero coverage and positive coverage reports
227
253
write_zero_cov (cov ['zero' ], cov_paths , cargs )
228
254
write_pos_cov (cov ['pos' ], cov_paths , cargs )
229
255
230
256
if not cargs .disable_lcov_web :
231
- gen_coverage (cov_paths , cargs )
257
+ lcov_gen_coverage (cov_paths , cargs )
232
258
gen_web_cov_report (fuzz_dir , cov_paths , cargs )
233
259
234
260
else :
@@ -496,7 +522,7 @@ def get_cycle_num(id_num, cargs):
496
522
497
523
return cycle_num
498
524
499
- def gen_coverage (cov_paths , cargs ):
525
+ def lcov_gen_coverage (cov_paths , cargs ):
500
526
501
527
out_lines = []
502
528
@@ -1029,7 +1055,9 @@ def parse_cmdline():
1029
1055
default = False )
1030
1056
p .add_argument ("--cover-corpus" , action = 'store_true' ,
1031
1057
help = "Measure coverage after running all available tests instead of individually per queue file" ,
1032
- # TODO: Document that queue limit should/will be ignored!
1058
+ default = False )
1059
+ p .add_argument ("--coverage-at-exit" , action = 'store_true' ,
1060
+ help = "Only calculate coverage just before afl-cov exit." ,
1033
1061
default = False )
1034
1062
p .add_argument ("--sleep" , type = int ,
1035
1063
help = "In --live mode, # of seconds to sleep between checking for new queue files" ,
0 commit comments