diff --git a/doc/fuzzing.md b/doc/fuzzing.md --- a/doc/fuzzing.md +++ b/doc/fuzzing.md @@ -48,15 +48,11 @@ ``` mkdir -p buildFuzzer cd buildFuzzer -cmake -GNinja .. -DCCACHE=OFF -DCMAKE_C_COMPILER=afl-gcc -DCMAKE_CXX_COMPILER=afl-g++ +cmake -GNinja .. -DCMAKE_C_COMPILER=afl-gcc -DCMAKE_CXX_COMPILER=afl-g++ export AFL_HARDEN=1 ninja bitcoin-fuzzers ``` -We disable ccache because we don't want to pollute the ccache with instrumented -objects, and similarly don't want to use non-instrumented cached objects linked -in. - The fuzzing can be sped up significantly (~200x) by using `afl-clang-fast` and `afl-clang-fast++` in place of `afl-gcc` and `afl-g++` when compiling. When compiling using `afl-clang-fast`/`afl-clang-fast++` the resulting @@ -88,7 +84,6 @@ mkdir -p buildFuzzer cd buildFuzzer cmake -GNinja .. \ - -DCCACHE=OFF \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DENABLE_SANITIZERS="fuzzer;address;undefined" diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -15,7 +15,9 @@ def main(): parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter) + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description='''Run the fuzz targets with all inputs from the seed_dir once.''', + ) parser.add_argument( "-l", "--loglevel", @@ -23,11 +25,6 @@ default="INFO", help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console.", ) - parser.add_argument( - '--export_coverage', - action='store_true', - help='If true, export coverage information to files in the seed corpus', - ) parser.add_argument( '--valgrind', action='store_true', @@ -42,6 +39,10 @@ nargs='*', help='The target(s) to run. Default is to run all targets.', ) + parser.add_argument( + '--m_dir', + help='Merge inputs from this directory into the seed_dir. Needs /target subdirectory.', + ) args = parser.parse_args() @@ -122,16 +123,44 @@ "subprocess timed out: Currently only libFuzzer is supported") sys.exit(1) + if args.m_dir: + merge_inputs( + corpus=args.seed_dir, + test_list=test_list_selection, + build_dir=config["environment"]["BUILDDIR"], + merge_dir=args.m_dir, + ) + run_once( corpus=args.seed_dir, test_list=test_list_selection, test_dir=test_dir, - export_coverage=args.export_coverage, use_valgrind=args.valgrind, ) -def run_once(*, corpus, test_list, test_dir, export_coverage, use_valgrind): +def merge_inputs(*, 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)) + for t in test_list: + args = [ + os.path.join(build_dir, 'src', 'test', 'fuzz', t), + '-merge=1', + os.path.join(corpus, t), + os.path.join(merge_dir, t), + ] + os.makedirs(os.path.join(corpus, 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 + logging.debug('Output: {}'.format(output)) + + +def run_once(*, corpus, test_list, test_dir, use_valgrind): for t in test_list: corpus_path = os.path.join(corpus, t) os.makedirs(corpus_path, exist_ok=True) @@ -155,13 +184,6 @@ output = result.stderr logging.debug('Output: {}'.format(output)) result.check_returncode() - if not export_coverage: - continue - for line in output.splitlines(): - if 'INITED' in line: - with open(os.path.join(corpus, t + '_coverage'), 'w', encoding='utf-8') as cov_file: - cov_file.write(line) - break if __name__ == '__main__':