partial bitcoin#18166: Run fuzz testing test cases (bitcoin-core/qa-assets) under valgrind to catch memory errors

This commit is contained in:
Kittywhiskers Van Gogh 2020-02-17 13:34:51 +00:00
parent b567c459e3
commit 66a400eef5

View File

@ -27,7 +27,12 @@ def main():
parser.add_argument( parser.add_argument(
'--valgrind', '--valgrind',
action='store_true', action='store_true',
help='If true, run fuzzing binaries under the valgrind memory error detector. Valgrind 3.14 or later required.', help='If true, run fuzzing binaries under the valgrind memory error detector',
)
parser.add_argument(
'-x',
'--exclude',
help="A comma-separated list of targets to exclude",
) )
parser.add_argument( parser.add_argument(
'seed_dir', 'seed_dir',
@ -67,7 +72,7 @@ def main():
logging.error("No fuzz targets found") logging.error("No fuzz targets found")
sys.exit(1) sys.exit(1)
logging.info("Fuzz targets found: {}".format(test_list_all)) logging.debug("{} fuzz target(s) found: {}".format(len(test_list_all), " ".join(sorted(test_list_all))))
args.target = args.target or test_list_all # By default run all args.target = args.target or test_list_all # By default run all
test_list_error = list(set(args.target).difference(set(test_list_all))) test_list_error = list(set(args.target).difference(set(test_list_all)))
@ -76,7 +81,15 @@ def main():
test_list_selection = list(set(test_list_all).intersection(set(args.target))) test_list_selection = list(set(test_list_all).intersection(set(args.target)))
if not test_list_selection: if not test_list_selection:
logging.error("No fuzz targets selected") logging.error("No fuzz targets selected")
logging.info("Fuzz targets selected: {}".format(test_list_selection)) if args.exclude:
for excluded_target in args.exclude.split(","):
if excluded_target not in test_list_selection:
logging.error("Target \"{}\" not found in current target list.".format(excluded_target))
continue
test_list_selection.remove(excluded_target)
test_list_selection.sort()
logging.info("{} of {} detected fuzz target(s) selected: {}".format(len(test_list_selection), len(test_list_all), " ".join(test_list_selection)))
test_list_seedless = [] test_list_seedless = []
for t in test_list_selection: for t in test_list_selection:
@ -151,16 +164,23 @@ def run_once(*, corpus, test_list, build_dir, use_valgrind):
args = [ args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', t), os.path.join(build_dir, 'src', 'test', 'fuzz', t),
'-runs=1', '-runs=1',
'-detect_leaks=0',
corpus_path, corpus_path,
] ]
if use_valgrind: if use_valgrind:
args = ['valgrind', '--quiet', '--error-exitcode=1', '--exit-on-first-error=yes'] + args args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
logging.debug('Run {} with args {}'.format(t, args)) logging.debug('Run {} with args {}'.format(t, args))
result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True) result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True)
output = result.stderr output = result.stderr
logging.debug('Output: {}'.format(output)) logging.debug('Output: {}'.format(output))
try:
result.check_returncode() result.check_returncode()
except subprocess.CalledProcessError as e:
if e.stdout:
logging.info(e.stdout)
if e.stderr:
logging.info(e.stderr)
logging.info("Target \"{}\" failed with exit code {}: {}".format(t, e.returncode, " ".join(args)))
sys.exit(1)
def parse_test_list(makefile): def parse_test_list(makefile):