Skip to content

Commit

Permalink
post-process: fix coverage issues (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidKorczynski committed Apr 27, 2022
1 parent 2e90e45 commit 06cebf2
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 34 deletions.
10 changes: 6 additions & 4 deletions post-processing/fuzz_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ def overlay_calltree_with_coverage(
# in which the callsite is placed.
callstack: Dict[int, str] = dict()

if profile.coverage is None:
return

def callstack_get_parent(n, c):
return c[int(n.depth) - 1]

Expand Down Expand Up @@ -117,7 +120,7 @@ def callstack_set_curr_node(n, name, c):
if not demangled_name == "LLVMFuzzerTestOneInput":
logger.error("LLVMFuzzerTestOneInput must be the first node in the calltree")
exit(1)
coverage_data = profile.get_function_coverage("LLVMFuzzerTestOneInput")
coverage_data = profile.coverage.get_hit_details("LLVMFuzzerTestOneInput")
if len(coverage_data) == 0:
logger.error("There is no coverage data (not even all negative).")
node.cov_parent = "EP"
Expand All @@ -129,9 +132,8 @@ def callstack_set_curr_node(n, name, c):
elif callstack_has_parent(node, callstack):
# Find the parent function and check coverage of the node
logger.debug("Extracting data")
coverage_data = profile.get_function_coverage(
fuzz_utils.normalise_str(callstack_get_parent(node, callstack)),
True
coverage_data = profile.coverage.get_hit_details(
fuzz_utils.normalise_str(callstack_get_parent(node, callstack))
)
for (n_line_number, hit_count_cov) in coverage_data:
logger.debug(f" - iterating {n_line_number} : {hit_count_cov}")
Expand Down
20 changes: 20 additions & 0 deletions post-processing/fuzz_cov_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class CoverageProfile:
Class for storing information about a runtime coverage report
"""
def __init__(self):
# Covmap is a dictionary of string to list of tuples of int.
# The tupls correspond to line number and hitcount in the
# source code.
self.covmap: Dict[str, List[Tuple[int, int]]] = dict()
self.covreports = list()

Expand All @@ -47,6 +50,23 @@ def is_func_hit(self, funcname):
return True
return False

def get_hit_details(self, funcname):
"""
Returns a list containiner tupls [line number, hit count]
of the function given as argument. If there is no coverage,
i.e. the function is not in the covmap of the coverage profile,
then an empty list is returned.
"""
fuzz_key = None
if funcname in self.covmap:
fuzz_key = funcname
elif fuzz_utils.demangle_cpp_func(funcname) in self.covmap:
fuzz_key = fuzz_utils.demangle_cpp_func(funcname)

if fuzz_key is None or fuzz_key not in self.covmap:
return []
return self.covmap[fuzz_key]

def get_hit_summary(self, funcname):
"""
returns the hit summary of a give function, in the form of
Expand Down
35 changes: 5 additions & 30 deletions post-processing/fuzz_data_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,35 +179,6 @@ def load_coverage(self, target_folder: str) -> None:
target_folder,
self.get_target_fuzzer_filename())

def get_function_coverage(self,
function_name: str,
should_normalise: bool = False) -> List[Tuple[int, int]]:
"""
Get the tuples reflecting coverage map of a given function
"""
logger.debug(f"getting function coverage of { function_name }")
if self.coverage is None:
logger.info("Returning None")
return []
if not should_normalise:
logger.debug("Should not normalise")
if function_name not in self.coverage.covmap:
return []
return self.coverage.covmap[function_name]

# should_normalise
logger.debug("Should normalise")
for funcname in self.coverage.covmap:
normalised_funcname = fuzz_utils.normalise_str(
fuzz_utils.demangle_cpp_func(fuzz_utils.normalise_str(funcname))
)
if normalised_funcname == function_name:
logger.debug(f"Found normalised: {normalised_funcname}")
return self.coverage.covmap[funcname]

# In case of errs return empty list
return []

def get_target_fuzzer_filename(self) -> str:
return self.fuzzer_source_file.split("/")[-1].replace(".cpp", "").replace(".c", "")

Expand Down Expand Up @@ -266,7 +237,11 @@ def get_cov_uncovered_reachable_funcs(self):

uncovered_funcs = []
for funcname in self.functions_reached_by_fuzzer:
if len(self.get_function_coverage(funcname)) == 0:
total_func_lines, hit_lines, hit_percentage = self.get_cov_metrics(funcname)
if total_func_lines is None:
uncovered_funcs.append(funcname)
continue
if hit_lines == 0:
uncovered_funcs.append(funcname)
return uncovered_funcs

Expand Down

0 comments on commit 06cebf2

Please sign in to comment.