mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-14 11:26:09 -05:00
fuzz: Run in parallel
This commit is contained in:
parent
c54295c1a2
commit
fa66280396
1 changed files with 51 additions and 24 deletions
|
@ -5,12 +5,13 @@
|
||||||
"""Run fuzz test targets.
|
"""Run fuzz test targets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -35,6 +36,12 @@ def main():
|
||||||
'--exclude',
|
'--exclude',
|
||||||
help="A comma-separated list of targets to exclude",
|
help="A comma-separated list of targets to exclude",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--par',
|
||||||
|
type=int,
|
||||||
|
default=4,
|
||||||
|
help='How many targets to merge or execute in parallel.',
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'seed_dir',
|
'seed_dir',
|
||||||
help='The seed corpus to run on (must contain subfolders for each fuzz target).',
|
help='The seed corpus to run on (must contain subfolders for each fuzz target).',
|
||||||
|
@ -124,8 +131,10 @@ def main():
|
||||||
logging.error("subprocess timed out: Currently only libFuzzer is supported")
|
logging.error("subprocess timed out: Currently only libFuzzer is supported")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=args.par) as fuzz_pool:
|
||||||
if args.m_dir:
|
if args.m_dir:
|
||||||
merge_inputs(
|
merge_inputs(
|
||||||
|
fuzz_pool=fuzz_pool,
|
||||||
corpus=args.seed_dir,
|
corpus=args.seed_dir,
|
||||||
test_list=test_list_selection,
|
test_list=test_list_selection,
|
||||||
build_dir=config["environment"]["BUILDDIR"],
|
build_dir=config["environment"]["BUILDDIR"],
|
||||||
|
@ -134,6 +143,7 @@ def main():
|
||||||
return
|
return
|
||||||
|
|
||||||
run_once(
|
run_once(
|
||||||
|
fuzz_pool=fuzz_pool,
|
||||||
corpus=args.seed_dir,
|
corpus=args.seed_dir,
|
||||||
test_list=test_list_selection,
|
test_list=test_list_selection,
|
||||||
build_dir=config["environment"]["BUILDDIR"],
|
build_dir=config["environment"]["BUILDDIR"],
|
||||||
|
@ -141,8 +151,9 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def merge_inputs(*, corpus, test_list, build_dir, merge_dir):
|
def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
|
||||||
logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
|
logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
|
||||||
|
jobs = []
|
||||||
for t in test_list:
|
for t in test_list:
|
||||||
args = [
|
args = [
|
||||||
os.path.join(build_dir, 'src', 'test', 'fuzz', t),
|
os.path.join(build_dir, 'src', 'test', 'fuzz', t),
|
||||||
|
@ -153,12 +164,20 @@ def merge_inputs(*, corpus, test_list, build_dir, merge_dir):
|
||||||
]
|
]
|
||||||
os.makedirs(os.path.join(corpus, t), exist_ok=True)
|
os.makedirs(os.path.join(corpus, t), exist_ok=True)
|
||||||
os.makedirs(os.path.join(merge_dir, t), exist_ok=True)
|
os.makedirs(os.path.join(merge_dir, t), exist_ok=True)
|
||||||
logging.debug('Run {} with args {}'.format(t, args))
|
|
||||||
output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr
|
def job(t, args):
|
||||||
logging.debug('Output: {}'.format(output))
|
output = 'Run {} with args {}\n'.format(t, " ".join(args))
|
||||||
|
output += subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr
|
||||||
|
logging.debug(output)
|
||||||
|
|
||||||
|
jobs.append(fuzz_pool.submit(job, t, args))
|
||||||
|
|
||||||
|
for future in as_completed(jobs):
|
||||||
|
future.result()
|
||||||
|
|
||||||
|
|
||||||
def run_once(*, corpus, test_list, build_dir, use_valgrind):
|
def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind):
|
||||||
|
jobs = []
|
||||||
for t in test_list:
|
for t in test_list:
|
||||||
corpus_path = os.path.join(corpus, t)
|
corpus_path = os.path.join(corpus, t)
|
||||||
os.makedirs(corpus_path, exist_ok=True)
|
os.makedirs(corpus_path, exist_ok=True)
|
||||||
|
@ -169,10 +188,18 @@ def run_once(*, corpus, test_list, build_dir, use_valgrind):
|
||||||
]
|
]
|
||||||
if use_valgrind:
|
if use_valgrind:
|
||||||
args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
|
args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
|
||||||
logging.debug('Run {} with args {}'.format(t, args))
|
|
||||||
|
def job(t, args):
|
||||||
|
output = '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))
|
return output, result
|
||||||
|
|
||||||
|
jobs.append(fuzz_pool.submit(job, t, args))
|
||||||
|
|
||||||
|
for future in as_completed(jobs):
|
||||||
|
output, result = future.result()
|
||||||
|
logging.debug(output)
|
||||||
try:
|
try:
|
||||||
result.check_returncode()
|
result.check_returncode()
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
@ -180,7 +207,7 @@ def run_once(*, corpus, test_list, build_dir, use_valgrind):
|
||||||
logging.info(e.stdout)
|
logging.info(e.stdout)
|
||||||
if e.stderr:
|
if e.stderr:
|
||||||
logging.info(e.stderr)
|
logging.info(e.stderr)
|
||||||
logging.info("Target \"{}\" failed with exit code {}: {}".format(t, e.returncode, " ".join(args)))
|
logging.info("Target \"{}\" failed with exit code {}".format(" ".join(result.args), e.returncode))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue