mirror of https://github.com/google/oss-fuzz.git
[ClusterFuzzLite] Fix fuzz target search for coverage (#6799)
Coverage uses a different mechanism for determining if a file is a fuzz target: It considers any executables in the top level of /out as fuzz targets. Fixes #6768
This commit is contained in:
parent
482a8e5314
commit
fb856de70b
|
@ -170,6 +170,38 @@ class PruneTargetRunner(BaseFuzzTargetRunner):
|
|||
fuzz_target_obj.free_disk_if_needed()
|
||||
|
||||
|
||||
NON_FUZZ_TARGETS_FOR_COVERAGE = {
|
||||
'llvm-symbolizer',
|
||||
'jazzer_agent_deploy.jar',
|
||||
'jazzer_driver',
|
||||
'jazzer_driver_with_sanitizer',
|
||||
}
|
||||
|
||||
|
||||
def is_coverage_fuzz_target(file_path):
|
||||
"""Returns whether |file_path| is a fuzz target binary for the purposes of a
|
||||
coverage report. Inspired by infra/base-images/base-runner/coverage."""
|
||||
if not os.path.isfile(file_path):
|
||||
return False
|
||||
if not utils.is_executable(file_path):
|
||||
return False
|
||||
filename = os.path.basename(file_path)
|
||||
return filename not in NON_FUZZ_TARGETS_FOR_COVERAGE
|
||||
|
||||
|
||||
def get_coverage_fuzz_targets(out):
|
||||
"""Returns a list of fuzz targets in |out| for coverage."""
|
||||
# We only want fuzz targets from the root because during the coverage build,
|
||||
# a lot of the image's filesystem is copied into /out for the purpose of
|
||||
# generating coverage reports.
|
||||
fuzz_targets = []
|
||||
for filename in os.listdir(out):
|
||||
file_path = os.path.join(out, filename)
|
||||
if is_coverage_fuzz_target(file_path):
|
||||
fuzz_targets.append(file_path)
|
||||
return fuzz_targets
|
||||
|
||||
|
||||
class CoverageTargetRunner(BaseFuzzTargetRunner):
|
||||
"""Runner that runs the 'coverage' command."""
|
||||
|
||||
|
@ -179,12 +211,7 @@ class CoverageTargetRunner(BaseFuzzTargetRunner):
|
|||
|
||||
def get_fuzz_targets(self):
|
||||
"""Returns fuzz targets in out directory."""
|
||||
# We only want fuzz targets from the root because during the coverage build,
|
||||
# a lot of the image's filesystem is copied into /out for the purpose of
|
||||
# generating coverage reports.
|
||||
# TOOD(metzman): Figure out if top_level_only should be the only behavior
|
||||
# for this function.
|
||||
return utils.get_fuzz_targets(self.workspace.out, top_level_only=True)
|
||||
return get_coverage_fuzz_targets(self.workspace.out)
|
||||
|
||||
def run_fuzz_targets(self):
|
||||
"""Generates a coverage report. Always returns False since it never finds
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
"""Tests for running fuzzers."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
@ -303,6 +304,31 @@ class BatchFuzzTargetRunnerTest(fake_filesystem_unittest.TestCase):
|
|||
self.assertEqual(mock_upload_crashes.call_count, 1)
|
||||
|
||||
|
||||
class GetCoverageTargetsTest(unittest.TestCase):
|
||||
"""Tests for get_coverage_fuzz_targets."""
|
||||
|
||||
def test_get_fuzz_targets(self):
|
||||
"""Tests that get_coverage_fuzz_targets returns expected targets."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Setup.
|
||||
fuzz_target_path = os.path.join(temp_dir, 'fuzz-target')
|
||||
with open(fuzz_target_path, 'w') as file_handle:
|
||||
file_handle.write('')
|
||||
fuzz_target_st = os.stat(fuzz_target_path)
|
||||
os.chmod(fuzz_target_path, fuzz_target_st.st_mode | stat.S_IEXEC)
|
||||
non_fuzz_target1 = os.path.join(temp_dir, 'non-fuzz-target1')
|
||||
with open(non_fuzz_target1, 'w') as file_handle:
|
||||
file_handle.write('LLVMFuzzerTestOneInput')
|
||||
subdir = os.path.join(temp_dir, 'subdir')
|
||||
os.mkdir(subdir)
|
||||
non_fuzz_target2 = os.path.join(subdir, 'non-fuzz-target1')
|
||||
with open(non_fuzz_target2, 'w') as file_handle:
|
||||
file_handle.write('LLVMFuzzerTestOneInput')
|
||||
|
||||
self.assertEqual(run_fuzzers.get_coverage_fuzz_targets(temp_dir),
|
||||
[fuzz_target_path])
|
||||
|
||||
|
||||
@unittest.skipIf(not os.getenv('INTEGRATION_TESTS'),
|
||||
'INTEGRATION_TESTS=1 not set')
|
||||
class CoverageReportIntegrationTest(unittest.TestCase):
|
||||
|
|
|
@ -94,12 +94,11 @@ def execute(command,
|
|||
return out, err, process.returncode
|
||||
|
||||
|
||||
def get_fuzz_targets(path, top_level_only=False):
|
||||
def get_fuzz_targets(path):
|
||||
"""Gets fuzz targets in a directory.
|
||||
|
||||
Args:
|
||||
path: A path to search for fuzz targets in.
|
||||
top_level_only: If True, only search |path|, do not recurse into subdirs.
|
||||
|
||||
Returns:
|
||||
A list of paths to fuzzers or an empty list if None.
|
||||
|
@ -108,9 +107,6 @@ def get_fuzz_targets(path, top_level_only=False):
|
|||
return []
|
||||
fuzz_target_paths = []
|
||||
for root, _, fuzzers in os.walk(path):
|
||||
if top_level_only and path != root:
|
||||
continue
|
||||
|
||||
for fuzzer in fuzzers:
|
||||
file_path = os.path.join(root, fuzzer)
|
||||
if is_fuzz_target_local(file_path):
|
||||
|
@ -134,6 +130,11 @@ def get_container_name():
|
|||
return file_handle.read().strip()
|
||||
|
||||
|
||||
def is_executable(file_path):
|
||||
"""Returns True if |file_path| is an exectuable."""
|
||||
return os.path.exists(file_path) and os.access(file_path, os.X_OK)
|
||||
|
||||
|
||||
def is_fuzz_target_local(file_path):
|
||||
"""Returns whether |file_path| is a fuzz target binary (local path).
|
||||
Copied from clusterfuzz src/python/bot/fuzzers/utils.py
|
||||
|
@ -154,7 +155,7 @@ def is_fuzz_target_local(file_path):
|
|||
# Ignore files with disallowed extensions (to prevent opening e.g. .zips).
|
||||
return False
|
||||
|
||||
if not os.path.exists(file_path) or not os.access(file_path, os.X_OK):
|
||||
if not is_executable(file_path):
|
||||
return False
|
||||
|
||||
if filename.endswith('_fuzzer'):
|
||||
|
|
Loading…
Reference in New Issue