File: confirm_fuzztests.py

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (89 lines) | stat: -rwxr-xr-x 2,912 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/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'
  process_result = subprocess.run([args.executable, '--list_fuzz_tests=1'],
                                  env=env,
                                  stdout=subprocess.PIPE,
                                  check=False)

  if 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.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()