blob: a27bf3b45cc4402df45a0b8d3a0d5b7e763d1f0b [file] [edit]
#!/usr/bin/env python3
#
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""List the fuzzers within a fuzztest and confirm they match what we expect.
Invoked by GN from fuzzer_test.gni.
"""
import argparse
import os
import re
import subprocess
import sys
# //build imports.
sys.path.append(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.pardir,
os.pardir,
'build',
)
)
import action_helpers
def CreateArgumentParser():
"""Creates an argparse.ArgumentParser instance."""
parser = argparse.ArgumentParser(description='Generate fuzztest fuzzers.')
parser.add_argument(
'--executable', help='Executable to interrogate for present fuzztests.'
)
parser.add_argument(
'--output',
help='Path to the output file (which will be intentionally blank).',
)
parser.add_argument(
'--fuzztests', nargs='+', help='List of fuzztests we expect to find.'
)
return parser
def main():
parser = CreateArgumentParser()
args = parser.parse_args()
expected_tests = set(args.fuzztests)
env = os.environ
env['ASAN_OPTIONS'] = 'detect_odr_violation=0'
try:
process_result = subprocess.run(
[args.executable, '--list_fuzz_tests=1'],
env=env,
stdout=subprocess.PIPE,
check=False,
)
except OSError:
process_result = None
if process_result and process_result.returncode == 0:
test_list = process_result.stdout.decode('utf-8')
actual_tests = re.findall('Fuzz test: (.*)', test_list)
# Gardeners may disable fuzztests by changing the names of the fuzztest
# in code to start with DISABLED_. We don't want gardeners to need to
# change gn files correspondingly, so strip such prefixes when checking
# that the test lists match.
actual_tests = {
test.strip().replace('DISABLED_', '').replace('FLAKY_', '')
for test in actual_tests
}
if expected_tests != actual_tests:
print(
'Unexpected fuzztests found in this binary.\nFuzztest binary: '
+ args.executable
+ '\n'
+ 'Expected fuzztests (as declared by the gn "fuzztests" variable on'
' this target): '
+ str(expected_tests)
+ '\nActual tests (as found in the binary): '
+ str(actual_tests)
+ '\nYou probably need to update the gn variable to match the tests'
' actually in the binary.'
)
sys.exit(-1)
# If we couldn't run the fuzztest binary itself, we'll
# regard that as fine. This is a best-efforts check that the
# gn 'fuzztests' variable is correct, and sometimes fuzzers don't
# run on LUCI e.g. due to lack of dependencies.
with action_helpers.atomic_output(args.output) as output:
output.write(''.encode('utf-8'))
if __name__ == '__main__':
main()