./test/fuzz/test_runner.py
after building as described in doc/fuzzing.md
./test/fuzz/test_runner.py
after building as described in doc/fuzzing.md
Concept ACK. Very nice!
Related: #10364 (“Feature request: Make Bitcoin libFuzzer-friendly and consider integration into the OSS-Fuzz project”). Feel free to collect the $20 000 USD bounty :-)
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
78+ ],
79+ check=True,
80+ stderr=subprocess.PIPE,
81+ universal_newlines=True,
82+ ).stderr
83+ if not "libFuzzer" in help_output:
if X not in Y
instead of if not X in Y
:-)
120+ corpus = corpi.pop(0)
121+ for t in test_list:
122+ args = [
123+ os.path.join(build_dir, 'src', 'test', 'fuzz', t),
124+ '-merge=1',
125+ '-runs=1', #??
#??
:-)
97+ test_list=test_list,
98+ build_dir=config["environment"]["BUILDDIR"],
99+ )
100+
101+
102+def run_once(*, corpus, test_list, build_dir, export_coverage):
export_coverage
unused?
26+ '--export_coverage',
27+ action='store_true',
28+ help='If true, export coverage information to files in the seed corpus',
29+ )
30+ parser.add_argument(
31+ 'corpi',
Nit: Isn’t corpora or corpuses the plural of corpus?
Perhaps the least unexpected choice is to go with “corpus” instead of “corpi” here?
s/corpi/corgi
100@@ -100,7 +101,7 @@ jobs:
101 PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev"
102 DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
103 GOAL="install"
104- BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-fuzz --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
105+ BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
Why the build parameter change for this existing test run?
oh I see, only removing --enable-fuzz
because it’s separated out
48+ # Read config generated by configure.
49+ config = configparser.ConfigParser()
50+ configfile = os.path.abspath(os.path.dirname(__file__)) + "/../config.ini"
51+ config.read_file(open(configfile, encoding="utf8"))
52+
53+ # Build list of tests
78+ test_list_selection = list(set(test_list_all).intersection(set(args.target)))
79+ if not test_list_selection:
80+ logging.error("No fuzz targets selected")
81+ logging.info("Fuzz targets selected: {}".format(test_list_selection))
82+
83+ if not config["components"].getboolean("ENABLE_FUZZ"):
23+
24+Only for AFL:
25+
26+```
27+mkdir outputs
28+AFLOUT=$PWD/outputs
export
for this one, but there is for DIR_FUZZ_IN
, is that intentional?
utACK fa7ca8ef58bf3e3b91d1f5a67fa42008e63b1f7b
Let’s get this merged :-)
Tested changes (https://github.com/bitcoin/bitcoin/pull/15295/commits/fa7ca8ef58bf3e3b91d1f5a67fa42008e63b1f7b) to doc/fuzzing.md
on Linux 4.15.0-43-generic [#46](/bitcoin-bitcoin/46/)-Ubuntu SMP x86_64
with afl-fuzz 2.52b
. Installed afl from scratch, rebuilt Bitcoin with requisite flags, and confirmed that running afl-fuzz
with the transaction_deserialize
works as intended.
Used new test_runner script which looks like an easy way to delegate to calling src/test/fuzz/*
. Have yet to get any meaningful output back, but maybe this is intended?
0$ ./test/fuzz/test_runner.py -l DEBUG ~/src/qa-assets/fuzz_seed_corpus transaction_deserialize
1
2Fuzz targets found: ['address_deserialize', 'addrman_deserialize', 'banentry_deserialize', 'block_deserialize', 'blockheader_deserialize', 'blocklocator_deserialize', 'blockmerkleroot', 'blocktransactions_deserialize', 'blocktransactionsrequest_deserialize', 'blockundo_deserialize', 'bloomfilter_deserialize', 'coins_deserialize', 'diskblockindex_deserialize', 'inv_deserialize', 'messageheader_deserialize', 'netaddr_deserialize', 'service_deserialize', 'transaction_deserialize', 'txoutcompressor_deserialize', 'txundo_deserialize']
3Fuzz targets selected: ['transaction_deserialize']
96+ ).stderr
97+ if "libFuzzer" not in help_output:
98+ logging.error("Must be built with libFuzzer")
99+ sys.exit(1)
100+ except subprocess.TimeoutExpired:
101+ logging.error("subprocess timed out: Currently only libFuzzer is supported")
Tested ACK https://github.com/bitcoin/bitcoin/pull/15295/commits/fa535af92c179b0ffb9280e0b2dc5acfeb80964a. Rebuilt with libfuzzer and tested the command that previously failed with afl:
0$ ./test/fuzz/test_runner.py -l DEBUG ~/src/qa-assets/fuzz_seed_corpus transaction_deserialize
1
2Fuzz targets found: ['address_deserialize', 'addrman_deserialize', 'banentry_deserialize', 'block_deserialize', 'blockheader_deserialize', 'blocklocator_deserialize', 'blockmerkleroot', 'blocktransactions_deserialize', 'blocktransactionsrequest_deserialize', 'blockundo_deserialize', 'bloomfilter_deserialize', 'coins_deserialize', 'diskblockindex_deserialize', 'inv_deserialize', 'messageheader_deserialize', 'netaddr_deserialize', 'service_deserialize', 'transaction_deserialize', 'txoutcompressor_deserialize', 'txundo_deserialize']
3Fuzz targets selected: ['transaction_deserialize']
4Run transaction_deserialize with args ['/home/james/src/bitcoin/src/test/fuzz/transaction_deserialize', '-runs=1', '/home/james/src/qa-assets/fuzz_seed_corpus/transaction_deserialize']
5Output: INFO: Seed: 819372946
6INFO: Loaded 1 modules (2002 inline 8-bit counters): 2002 [0x55b9cec15620, 0x55b9cec15df2),
7INFO: Loaded 1 PC tables (2002 PCs): 2002 [0x55b9cec15df8,0x55b9cec1db18),
8INFO: 295 files found in /home/james/src/qa-assets/fuzz_seed_corpus/transaction_deserialize
9INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 52575 bytes
10INFO: seed corpus: files: 295 min: 1b max: 52575b total: 491499b rss: 45Mb
11[#296](/bitcoin-bitcoin/296/) INITED cov: 240 ft: 938 corp: 277/475Kb exec/s: 0 rss: 106Mb
12[#296](/bitcoin-bitcoin/296/) DONE cov: 240 ft: 938 corp: 277/475Kb exec/s: 0 rss: 106Mb
13Done 296 runs in 0 second(s)
Worth noting that I had to bump clang from 4. to 6. in order for the -fsanitize=fuzzer
flags to work.
26@@ -28,6 +27,8 @@ FUZZ_TARGETS = \
27
28 if ENABLE_FUZZ
29 noinst_PROGRAMS += $(FUZZ_TARGETS:=)
30+else
31+bin_PROGRAMS += test/test_bitcoin
Yes, I think there is no reason to build test_bitcoin
if you want to build the fuzz tests. Am I missing something?
Regardless of that, it would result in linker errors later in the build process, since you can’t link libfuzzer to something that has a main function.
test_bitcoin
in this case.
Yes, ideally it should disable all other binaries.
Currently we hack around that by specifying it manually:
https://github.com/bitcoin/bitcoin/blob/169dced9a42bd741b3265adee23e6a8d1f852227/.travis.yml#L146
It is surprising that –enable-fuzz silently stops building the test binary
Might be fixed by #19388, which is blocked on #20560 . Though when building and linking with a fuzz engine, the test_bitcoin binary won’t have any meaning. Not sure if it will even compile/link.
config.log continues to claim that test_bitcoin is being built.
I don’t really understand build systems, so if this is an issue, I hope that someone will fix it
I’ll open a PR to change config to output something like
0configure:27478: checking whether to build test_bitcoin-qt
1configure:27481: result: no, because fuzzing is enabled
2configure:27499: checking whether to build test_bitcoin
3configure:27502: result: no, because fuzzing is enabled
It’s not really surprising that enabling fuzzing would break all the other binaries, I was just misled by the config output.