From a3b539a924f8611abb3096f2bd9d35094b5577e3 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 17 Feb 2020 13:34:51 +0000 Subject: [PATCH 1/5] ci: Run fuzz testing test cases under valgrind --- .travis.yml | 5 +++++ .../00_setup_env_native_fuzz_with_valgrind.sh | 18 ++++++++++++++++++ ci/test/06_script_b.sh | 2 +- test/fuzz/test_runner.py | 4 ++-- 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 ci/test/00_setup_env_native_fuzz_with_valgrind.sh diff --git a/.travis.yml b/.travis.yml index c5b8c476b7e..9a111c03add 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,6 +134,11 @@ jobs: env: >- FILE_ENV="./ci/test/00_setup_env_native_fuzz.sh" + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, fuzzers under valgrind]' + env: >- + FILE_ENV="./ci/test/00_setup_env_native_fuzz_with_valgrind.sh" + - stage: test name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' env: >- diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh new file mode 100644 index 00000000000..45b13a669d6 --- /dev/null +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_native_fuzz_valgrind +export PACKAGES="clang-8 llvm-8 python3 libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev valgrind" +export NO_DEPENDS=1 +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false +export RUN_FUZZ_TESTS=true +export FUZZ_TESTS_CONFIG="--valgrind" +export GOAL="install" +export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-8 CXX=clang++-8" +# Use clang-8, instead of default clang on bionic, which is clang-6 and does not come with libfuzzer on aarch64 diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh index 537493a7103..3b32513353a 100755 --- a/ci/test/06_script_b.sh +++ b/ci/test/06_script_b.sh @@ -36,6 +36,6 @@ fi if [ "$RUN_FUZZ_TESTS" = "true" ]; then BEGIN_FOLD fuzz-tests - DOCKER_EXEC test/fuzz/test_runner.py -l DEBUG ${DIR_FUZZ_IN} + DOCKER_EXEC test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} -l DEBUG ${DIR_FUZZ_IN} END_FOLD fi diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 61c3e700c57..b638e6bac62 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -64,7 +64,7 @@ def main(): parser.add_argument( '--valgrind', 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( 'seed_dir', @@ -150,7 +150,7 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind): corpus_path, ] 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)) result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True) output = result.stderr From 555236f769c13518db70f5df36e5688d63486bd5 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 19 Feb 2020 13:36:03 +0000 Subject: [PATCH 2/5] tests: Remove -detect_leaks=0 from test/fuzz/test_runner.py - no longer needed --- test/fuzz/test_runner.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index b638e6bac62..5174e21e2a9 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -146,7 +146,6 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind): args = [ os.path.join(build_dir, 'src', 'test', 'fuzz', t), '-runs=1', - '-detect_leaks=0', corpus_path, ] if use_valgrind: From 5ea81449f30a6fe6db3b6df5e8009f21a782ff44 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 19 Feb 2020 14:10:22 +0000 Subject: [PATCH 3/5] tests: Add support for excluding fuzz targets using -x/--exclude --- test/fuzz/test_runner.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 5174e21e2a9..0f7a349e450 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -47,6 +47,7 @@ FUZZERS_MISSING_CORPORA = [ "tx_out", ] + def main(): parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( @@ -66,6 +67,11 @@ def main(): action='store_true', 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( 'seed_dir', help='The seed corpus to run on (must contain subfolders for each fuzz target).', @@ -100,7 +106,7 @@ def main(): logging.error("No fuzz targets found") 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 test_list_error = list(set(args.target).difference(set(test_list_all))) @@ -109,7 +115,15 @@ def main(): test_list_selection = list(set(test_list_all).intersection(set(args.target))) if not test_list_selection: 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))) try: help_output = subprocess.run( From 733bbec34fbec85574cc456832b2b2f807e5dce9 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 19 Feb 2020 14:11:54 +0000 Subject: [PATCH 4/5] tests: Add --exclude integer,parse_iso8601 (temporarily) to make Travis pass until uninitialized read issue in FormatISO8601DateTime is fixed --- ci/test/00_setup_env_native_fuzz_with_valgrind.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh index 45b13a669d6..6e1c400d507 100644 --- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh +++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh @@ -12,7 +12,7 @@ export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false export RUN_FUZZ_TESTS=true -export FUZZ_TESTS_CONFIG="--valgrind" +export FUZZ_TESTS_CONFIG="--exclude integer,parse_iso8601 --valgrind" export GOAL="install" export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang-8 CXX=clang++-8" # Use clang-8, instead of default clang on bionic, which is clang-6 and does not come with libfuzzer on aarch64 From f2472f64604a0c583f950c56e8753d0bee246388 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 19 Feb 2020 14:27:19 +0000 Subject: [PATCH 5/5] tests: Improve test runner output in case of target errors --- test/fuzz/test_runner.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 0f7a349e450..a56651cca56 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -168,7 +168,15 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind): result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True) output = result.stderr logging.debug('Output: {}'.format(output)) - result.check_returncode() + try: + 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) if not export_coverage: continue for l in output.splitlines():