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