Skip to content

Commit c5b9561

Browse files
authored
add coverage error reports to overview (#2214)
Signed-off-by: phi-go <[email protected]>
1 parent 02bbc30 commit c5b9561

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

tools/web-fuzzing-introspection/app/static/assets/db/oss_fuzz.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ def get_fuzzer_stats_fuzz_count_url(project_name, date_str):
7676
return coverage_targets
7777

7878

79+
def get_fuzzer_target_coverage_error_log_url(project_name, date_str, target):
80+
'''Get the url for the potential errors that are encountered during coverage measurement of a target.
81+
Note that if the file does not exist, no errors have been recorded.'''
82+
base_url = 'https://storage.googleapis.com/oss-fuzz-coverage/{0}/fuzzer_stats/{1}/{2}_error.log'
83+
url = base_url.format(project_name, date_str, target)
84+
return url
85+
86+
7987
def get_introspector_project_tests_url(project_name, datestr):
8088
return get_introspector_report_url_base(project_name,
8189
datestr) + "light/all_tests.json"
@@ -385,6 +393,17 @@ def get_fuzzer_code_coverage_summary(project_name, datestr, fuzzer):
385393
return None
386394

387395

396+
def get_fuzzer_target_coverage_error_log(project_name, datestr, fuzzer):
397+
url = get_fuzzer_target_coverage_error_log_url(project_name, datestr,
398+
fuzzer)
399+
try:
400+
response = requests.get(url, timeout=20)
401+
if response.status_code == 200:
402+
return response.text.strip()
403+
except Exception as e:
404+
return None
405+
406+
388407
MAGNITUDES = {
389408
"k": 10**(3 * 1),
390409
"M": 10**(3 * 2),

tools/web-fuzzing-introspection/app/static/assets/db/web_db_creator_from_summary.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@
6969
logger = logging.getLogger(name=__name__)
7070

7171

72+
def parse_coverage_error(error_log: str) -> str:
73+
"""Parse coverage error log to extract the first error cause with details.
74+
75+
Examples:
76+
- "==140== ERROR: libFuzzer: out-of-memory (used: 2108Mb; limit: 2048Mb)"
77+
-> "out-of-memory (used: 2108Mb; limit: 2048Mb)"
78+
- "==10925== ERROR: libFuzzer: timeout after 1 seconds"
79+
-> "timeout (used: 120s; limit: 100s)"
80+
"""
81+
import re
82+
83+
# Pattern to match libFuzzer error messages
84+
# Captures everything after "ERROR: libFuzzer: "
85+
pattern = r'==\d+== ERROR: libFuzzer: (.*?)(?:\n|$)'
86+
87+
match = re.search(pattern, error_log)
88+
if match:
89+
return match.group(1).strip()
90+
91+
# Fallback: if no pattern matches, return the original error_log
92+
return error_log
93+
94+
7295
def git_clone_project(git_url: str,
7396
destination: str,
7497
single_depth: bool = True) -> bool:
@@ -792,6 +815,14 @@ def extract_project_data(project_name, date_str, should_include_details,
792815

793816
amount_of_fuzzers = len(all_fuzzers)
794817
for ff in all_fuzzers:
818+
per_fuzzer_cov_result = {}
819+
try:
820+
fuzzer_coverage_error_log = oss_fuzz.get_fuzzer_target_coverage_error_log(
821+
project_name, date_str.replace("-", ""), ff)
822+
except:
823+
fuzzer_coverage_error_log = None
824+
per_fuzzer_cov_result['error_log'] = fuzzer_coverage_error_log
825+
795826
try:
796827
fuzzer_corpus_size = oss_fuzz.get_fuzzer_corpus_size(
797828
project_name, date_str.replace("-", ""), ff,
@@ -805,9 +836,11 @@ def extract_project_data(project_name, date_str, should_include_details,
805836
fuzzer_cov_data = extract_code_coverage_data(fuzzer_cov)
806837
if fuzzer_cov_data is not None:
807838
fuzzer_cov_data['corpus_size'] = fuzzer_corpus_size
808-
per_fuzzer_cov[ff] = fuzzer_cov_data
839+
per_fuzzer_cov_result['fuzzer_cov_data'] = fuzzer_cov_data
809840
except:
810-
pass
841+
per_fuzzer_cov_result['fuzzer_cov_data'] = None
842+
843+
per_fuzzer_cov[ff] = per_fuzzer_cov_result
811844

812845
project_timestamp = {
813846
"project_name": project_name,
@@ -1039,6 +1072,12 @@ def per_fuzzer_coverage_analysis(project_name: str,
10391072
data, project_name, ff)
10401073
except:
10411074
days_degraded = []
1075+
try:
1076+
coverage_error = data[-1]['error_log']
1077+
if coverage_error:
1078+
coverage_error = parse_coverage_error(coverage_error)
1079+
except:
1080+
coverage_error = None
10421081
results[ff] = {
10431082
'report_url': report_url,
10441083
'report_date': latest_date_with_value,
@@ -1055,6 +1094,7 @@ def per_fuzzer_coverage_analysis(project_name: str,
10551094
(max_cov - current) > FUZZER_COVERAGE_IS_DEGRADED,
10561095
'days_degraded': days_degraded,
10571096
'got_lost': ff in lost_fuzzers,
1097+
'coverage_error': coverage_error,
10581098
}
10591099
return results
10601100

@@ -1086,7 +1126,9 @@ def calculate_recent_results(projects_with_new_results, timestamps,
10861126
fuzzers_past |= fuzzers_current
10871127
fuzzers_current = set(per_fuzzer_coverage_data.keys())
10881128

1089-
for ff, cov_data in per_fuzzer_coverage_data.items():
1129+
for ff, ff_data in per_fuzzer_coverage_data.items():
1130+
cov_data = ff_data['fuzzer_cov_data']
1131+
error_log = ff_data['error_log']
10901132
try:
10911133
perc = round(
10921134
100 * cov_data['covered'] / cov_data['count'], 2)
@@ -1102,8 +1144,10 @@ def calculate_recent_results(projects_with_new_results, timestamps,
11021144
cov_data['count'],
11031145
'percentage':
11041146
perc,
1147+
'error_log':
1148+
error_log,
11051149
'date':
1106-
do
1150+
do,
11071151
})
11081152
except:
11091153
continue

tools/web-fuzzing-introspection/app/webapp/templates/project-profile.html

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,39 +136,42 @@ <h2>Project: <a href="{{project_url}}"> {{ project.name }}</a></h2>
136136
<div style="max-height: 30rem; overflow: auto; margin-top: 1.5rem">
137137
<table style="width: 100%;">
138138
<thead>
139-
<th style="padding: 0 0.5rem;">Fuzzer</th>
140-
<th style="padding: 0 0.5rem;">Code coverage (lines)</th>
141-
<th style="padding: 0 0.5rem;">Latest Report</th>
142-
<th style="padding: 0 0.5rem;">Comments</th>
139+
<th style="padding: 0.5rem 0.5rem;">Fuzzer</th>
140+
<th style="padding: 0.5rem 0.5rem;">Code coverage (lines)</th>
141+
<th style="padding: 0.5rem 0.5rem;">Latest Report</th>
142+
<th style="padding: 0.5rem 0.5rem;">Comments</th>
143143
</thead>
144144
<tbody>
145145
{% for fuzzer, fuzzer_data in project.recent_results.items()
146146
|sort(attribute='0')
147147
|sort(reverse=true, attribute='1.got_lost,1.has_degraded')
148148
%}
149149
<tr
150-
{% if fuzzer_data['got_lost'] or fuzzer_data['max_has_degraded'] %}
150+
{% if fuzzer_data['got_lost'] or fuzzer_data['max_has_degraded'] or fuzzer_data['coverage_error'] %}
151151
class="alert alert-danger" role="alert"
152152
{% endif %}
153153
>
154-
<td style="padding: 0 0.5rem;">
154+
<td style="padding: 0.2rem 0.2rem;">
155155
{{fuzzer}} (<a href="#perFuzzerCoverageLinesOverTimePlot{{ fuzzer_data['hashed_name'] }}">plot</a>)
156156
</td>
157-
<td style="padding: 0 0.5rem;">
157+
<td style="padding: 0.2rem 0.2rem;">
158158
<code style="color: unset; white-space: nowrap;">
159159
{{ fuzzer_data['current'] }}% (avg: {{ fuzzer_data['avg'] }}%, max: {{ fuzzer_data['max'] }}%)
160160
</code>
161161
</td>
162-
<td style="padding: 0 0.5rem;">
162+
<td style="padding: 0.2rem 0.2rem;">
163163
<a href="{{fuzzer_data['report_url']}}">{{ fuzzer_data['report_date'] }}</a>
164164
</td>
165-
<td style="padding: 0 0.5rem;">
165+
<td style="padding: 0.2rem 0.2rem;">
166166
{% if fuzzer_data['got_lost'] %}
167167
Fuzzer no longer available!<br>
168168
{% endif %}
169169
{% if fuzzer_data['max_has_degraded'] %}
170170
Coverage has degraded!<br>
171171
{% endif %}
172+
{% if fuzzer_data['coverage_error'] %}
173+
Coverage error: {{ fuzzer_data['coverage_error'] }}<br>
174+
{% endif %}
172175
{% for day_degraded in fuzzer_data['days_degraded'] %}
173176
Degraded from <a href="{{ day_degraded['before_url'] }}">{{day_degraded['before_date']}} ({{day_degraded['before_perc']}}%)</a>
174177
to <a href="{{ day_degraded['current_url'] }}">{{day_degraded['current_date']}} ({{day_degraded['current_perc']}}%)</a>!<br>

0 commit comments

Comments
 (0)