xref: /aosp_15_r20/external/cronet/testing/libfuzzer/confirm_fuzztests.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env python3
2#
3# Copyright 2024 The Chromium Authors
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""List the fuzzers within a fuzztest and confirm they match what we expect.
7
8Invoked by GN from fuzzer_test.gni.
9"""
10
11import argparse
12import os
13import re
14import subprocess
15import sys
16
17# Set up path to be able to import action_helpers
18sys.path.append(
19    os.path.join(
20        os.path.dirname(os.path.abspath(__file__)),
21        os.pardir,
22        os.pardir,
23        'build',
24    )
25)
26import action_helpers
27
28
29def CreateArgumentParser():
30  """Creates an argparse.ArgumentParser instance."""
31  parser = argparse.ArgumentParser(description='Generate fuzztest fuzzers.')
32  parser.add_argument(
33      '--executable', help='Executable to interrogate for present fuzztests.'
34  )
35  parser.add_argument(
36      '--output',
37      help='Path to the output file (which will be intentionally blank).',
38  )
39  parser.add_argument(
40      '--fuzztests', nargs='+', help='List of fuzztests we expect to find.'
41  )
42  return parser
43
44
45def main():
46  parser = CreateArgumentParser()
47  args = parser.parse_args()
48
49  expected_tests = set(args.fuzztests)
50
51  env = os.environ
52  env['ASAN_OPTIONS'] = 'detect_odr_violation=0'
53  process_result = subprocess.run(
54      [args.executable, '--list_fuzz_tests'],
55      env=env, stdout=subprocess.PIPE, check=False
56  )
57
58  if process_result.returncode == 0:
59    test_list = process_result.stdout.decode('utf-8')
60
61    actual_tests = set(re.findall('Fuzz test: (.*)', test_list))
62
63    if expected_tests != actual_tests:
64      print(
65          'Unexpected fuzztests found in this binary.\nFuzztest binary: '
66          + args.executable
67          + '\n'
68          + 'Expected fuzztests (as declared by the gn "fuzztests" variable on'
69          ' this target): '
70          + str(expected_tests)
71          + '\nActual tests (as found in the binary): '
72          + str(actual_tests)
73          + '\nYou probably need to update the gn variable to match the tests'
74          ' actually in the binary.'
75      )
76      sys.exit(-1)
77
78  # If we couldn't run the fuzztest binary itself, we'll
79  # regard that as fine. This is a best-efforts check that the
80  # gn 'fuzztests' variable is correct, and sometimes fuzzers don't
81  # run on LUCI e.g. due to lack of dependencies.
82
83  with action_helpers.atomic_output(args.output) as output:
84    output.write(''.encode('utf-8'))
85
86
87if __name__ == '__main__':
88  main()
89