Skip to content

Commit e6cb617

Browse files
post-processing: enable reading of Python output (#295)
* post-processing: enable reading of Python output This provides a few minor changes and some bug fixes, which enables reading of the Python frontend's output as is. There will have to be further changes to make the project more friendly for having data from sources in different languages. Ref: #280 * nits * nit * nits
1 parent cfd5a75 commit e6cb617

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

post-processing/fuzz_analysis.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,9 @@ def callstack_set_curr_node(n, name, c):
139139
# hardcoding LLVMFuzzerTestOneInput to be green because some fuzzers may not
140140
# have a single seed, and in this specific case LLVMFuzzerTestOneInput
141141
# will be red.
142-
if not demangled_name == "LLVMFuzzerTestOneInput":
143-
logger.error("LLVMFuzzerTestOneInput must be the first node in the calltree")
142+
if demangled_name != "LLVMFuzzerTestOneInput" and "TestOneInput" not in demangled_name:
143+
logger.info("Unexpected first node in the calltree.")
144+
logger.info(f"Found: {demangled_name}")
144145
exit(1)
145146
coverage_data = profile.coverage.get_hit_details("LLVMFuzzerTestOneInput")
146147
if len(coverage_data) == 0:

post-processing/fuzz_data_loader.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ def __init__(self, filename: str, data_dict_yaml: Dict[Any, Any]):
160160
)
161161

162162
func_profile = FunctionProfile(elem)
163+
logger.info(f"Adding {func_profile.function_name}")
163164
self.all_class_functions[func_profile.function_name] = func_profile
164165

165166
def refine_paths(self, basefolder: str) -> None:
@@ -187,9 +188,21 @@ def set_all_reached_functions(self) -> None:
187188
sets self.functions_reached_by_fuzzer to all functions reached
188189
by LLVMFuzzerTestOneInput
189190
"""
190-
self.functions_reached_by_fuzzer = (self
191-
.all_class_functions["LLVMFuzzerTestOneInput"]
192-
.functions_reached)
191+
if "LLVMFuzzerTestOneInput" in self.all_class_functions:
192+
self.functions_reached_by_fuzzer = (
193+
self.all_class_functions["LLVMFuzzerTestOneInput"].functions_reached
194+
)
195+
return
196+
197+
# Find Python entrypoint
198+
for func_name in self.all_class_functions:
199+
if "TestOneInput" in func_name:
200+
reached = self.all_class_functions[func_name].functions_reached
201+
self.functions_reached_by_fuzzer = reached
202+
return
203+
204+
# TODO: make fuzz-introspector exceptions
205+
raise Exception
193206

194207
def reaches(self, func_name: str) -> bool:
195208
return func_name in self.functions_reached_by_fuzzer
@@ -495,12 +508,21 @@ def get_function_summaries(self) -> Tuple[int, int, int, float, float]:
495508
)
496509

497510
def get_complexity_summaries(self) -> Tuple[int, int, int, float, float]:
498-
499511
complexity_reached, complexity_unreached = self.get_total_complexity()
500512
total_complexity = complexity_unreached + complexity_reached
501513

502-
reached_complexity_percentage = (float(complexity_reached) / (total_complexity)) * 100.0
503-
unreached_complexity_percentage = (float(complexity_unreached) / (total_complexity)) * 100.0
514+
try:
515+
reached_complexity_percentage = (float(complexity_reached) / (total_complexity)) * 100.0
516+
except Exception:
517+
logger.info("Total complexity is 0")
518+
reached_complexity_percentage = 0
519+
try:
520+
unreached_complexity_percentage = (
521+
(float(complexity_unreached) / (total_complexity)) * 100.0
522+
)
523+
except Exception:
524+
logger.info("Total complexity is 0")
525+
unreached_complexity_percentage = 0
504526

505527
return (
506528
total_complexity,
@@ -560,10 +582,19 @@ def read_fuzzer_data_file_to_profile(filename: str) -> Optional[FuzzerProfile]:
560582
return None
561583

562584
FP = FuzzerProfile(filename, data_dict_yaml)
563-
if "LLVMFuzzerTestOneInput" not in FP.all_class_functions:
564-
return None
565585

566-
return FP
586+
# Check we have a valid entrypoint
587+
if "LLVMFuzzerTestOneInput" in FP.all_class_functions:
588+
return FP
589+
590+
# Check for python fuzzers. The following assumes the entrypoint
591+
# currently has "TestOneInput" int its name
592+
for name in FP.all_class_functions:
593+
if "TestOneInput" in name:
594+
return FP
595+
596+
logger.info("Found no fuzzer entrypoints")
597+
return None
567598

568599

569600
def add_func_to_reached_and_clone(merged_profile_old: MergedProjectProfile,

post-processing/fuzz_html.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,11 @@ def create_fuzzer_detailed_section(
624624
uncovered_reachable_funcs = len(profile.get_cov_uncovered_reachable_funcs())
625625
reachable_funcs = len(profile.functions_reached_by_fuzzer)
626626
reached_funcs = reachable_funcs - uncovered_reachable_funcs
627-
cov_reach_proportion = (float(reached_funcs) / float(reachable_funcs)) * 100.0
627+
try:
628+
cov_reach_proportion = (float(reached_funcs) / float(reachable_funcs)) * 100.0
629+
except Exception:
630+
logger.info("reachable funcs is 0")
631+
cov_reach_proportion = 0.0
628632
str_percentage = "%.5s%%" % str(cov_reach_proportion)
629633
fuzz_utils.write_to_summary_file(
630634
profile.get_key(),

0 commit comments

Comments
 (0)