Skip to content

Commit

Permalink
Merge #18300: fuzz: Add option to merge input dir to test runner
Browse files Browse the repository at this point in the history
fa3fa27 fuzz: Remove option --export_coverage from test_runner (MarcoFalke)
aaaa055 fuzz: Add option to merge input dir to test runner (MarcoFalke)
fa4fa88 doc: Remove --disable-ccache from docs (MarcoFalke)

Pull request description:

  This is mainly useful for myself to merge pull requests like bitcoin-core/qa-assets#4

  I thought it wouldn't hurt to share the code.

  Also remove the `--disable-ccache` from the docs to speed up builds when developing fuzzers.

Top commit has no ACKs.

Tree-SHA512: 818d85a90db86a7f4e8b001cc88342e5b28b02029d2bd4174440b28a8c4cc29b5406bd6348f72ddf909bb3d0f9bf7b1011976f6480e4418c8b7da5ecccae93e8
  • Loading branch information
MarcoFalke committed Mar 18, 2020
2 parents e83a1de + fa3fa27 commit 5c9d408
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 19 deletions.
8 changes: 4 additions & 4 deletions doc/fuzzing.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ For macOS you may need to ignore x86 compilation checks when running `make`:
To build Bitcoin Core using AFL instrumentation (this assumes that the
`AFLPATH` was set as above):
```
./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
./configure --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
export AFL_HARDEN=1
make
```

If you are using clang you will need to substitute `afl-gcc` with `afl-clang`
and `afl-g++` with `afl-clang++`, so the first line above becomes:
```
./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-clang CXX=${AFLPATH}/afl-clang++
./configure --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-clang CXX=${AFLPATH}/afl-clang++
```

We disable ccache because we don't want to pollute the ccache with instrumented
Expand Down Expand Up @@ -102,7 +102,7 @@ libFuzzer is needed (all found in the `compiler-rt` runtime libraries package).
To build all fuzz targets with libFuzzer, run

```
./configure --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++
./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++
make
```

Expand Down Expand Up @@ -134,5 +134,5 @@ clang does not come first in your path.

Full configure that was tested on macOS Catalina with `brew` installed `llvm`:
```
./configure --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm
./configure --enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++ --disable-asm
```
48 changes: 33 additions & 15 deletions test/fuzz/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@


def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='''Run the fuzz targets with all inputs from the seed_dir once.''',
)
parser.add_argument(
"-l",
"--loglevel",
dest="loglevel",
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',
Expand All @@ -46,6 +44,10 @@ def main():
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()

Expand Down Expand Up @@ -122,16 +124,39 @@ def main():
logging.error("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,
build_dir=config["environment"]["BUILDDIR"],
export_coverage=args.export_coverage,
use_valgrind=args.valgrind,
)


def run_once(*, corpus, test_list, build_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, build_dir, use_valgrind):
for t in test_list:
corpus_path = os.path.join(corpus, t)
os.makedirs(corpus_path, exist_ok=True)
Expand All @@ -155,13 +180,6 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind):
logging.info(e.stderr)
logging.info("Target \"{}\" failed with exit code {}: {}".format(t, e.returncode, " ".join(args)))
sys.exit(1)
if not export_coverage:
continue
for l in output.splitlines():
if 'INITED' in l:
with open(os.path.join(corpus, t + '_coverage'), 'w', encoding='utf-8') as cov_file:
cov_file.write(l)
break


def parse_test_list(makefile):
Expand Down

0 comments on commit 5c9d408

Please sign in to comment.