mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-19 05:45:05 +01:00
Merge bitcoin/bitcoin#28015: fuzz: Generate rpc fuzz targets individually
fa1e27fe8e
fuzz: Generate rpc fuzz targets individually (MarcoFalke) Pull request description: The `rpc` fuzz target was added more than two years ago ine45863166f
. However, the bug https://github.com/bitcoin/bitcoin/issues/27913 was only found recently. Thus, it is pretty clear that fuzz engines can't deal with a search space that is too broad and can be extended in too many directions. Fix that by limiting the search space to each RPC method name and then iterate over all names, instead of letting the fuzz engine do the iteration. With this, the bug can be found in seconds, as opposed to years of CPU time (or never). ACKs for top commit: brunoerg: ACKfa1e27fe8e
dergoegge: ACKfa1e27fe8e
Tree-SHA512: 45ccba842367650d010320603153276b1b303deda9ba8c6bb31a4d2473b00aa5bca866db95f541485d65efd8276e2575026968c037872ef344fa33cf45bcdcd7
This commit is contained in:
commit
cf4da5ec29
@ -200,29 +200,47 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
|
|||||||
{corpus_dir}.
|
{corpus_dir}.
|
||||||
"""
|
"""
|
||||||
logging.info("Generating corpus to {}".format(corpus_dir))
|
logging.info("Generating corpus to {}".format(corpus_dir))
|
||||||
|
rpc_target = "rpc"
|
||||||
|
has_rpc = rpc_target in targets
|
||||||
|
if has_rpc:
|
||||||
|
targets.remove(rpc_target)
|
||||||
|
targets = [(t, {}) for t in targets]
|
||||||
|
if has_rpc:
|
||||||
|
lines = subprocess.run(
|
||||||
|
["git", "grep", "--function-context", "RPC_COMMANDS_SAFE_FOR_FUZZING{", os.path.join(src_dir, "src", "test", "fuzz", "rpc.cpp")],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
).stdout.splitlines()
|
||||||
|
lines = [l.split("\"", 1)[1].split("\"")[0] for l in lines if l.startswith("src/test/fuzz/rpc.cpp- \"")]
|
||||||
|
targets += [(rpc_target, {"LIMIT_TO_RPC_COMMAND": r}) for r in lines]
|
||||||
|
|
||||||
def job(command, t):
|
def job(command, t, t_env):
|
||||||
logging.debug("Running '{}'\n".format(" ".join(command)))
|
logging.debug(f"Running '{command}'")
|
||||||
logging.debug("Command '{}' output:\n'{}'\n".format(
|
logging.debug("Command '{}' output:\n'{}'\n".format(
|
||||||
' '.join(command),
|
command,
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
command,
|
command,
|
||||||
env=get_fuzz_env(target=t, source_dir=src_dir),
|
env={
|
||||||
|
**t_env,
|
||||||
|
**get_fuzz_env(target=t, source_dir=src_dir),
|
||||||
|
},
|
||||||
check=True,
|
check=True,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
text=True,
|
text=True,
|
||||||
).stderr))
|
).stderr,
|
||||||
|
))
|
||||||
|
|
||||||
futures = []
|
futures = []
|
||||||
for target in targets:
|
for target, t_env in targets:
|
||||||
target_corpus_dir = os.path.join(corpus_dir, target)
|
target_corpus_dir = corpus_dir / target
|
||||||
os.makedirs(target_corpus_dir, exist_ok=True)
|
os.makedirs(target_corpus_dir, exist_ok=True)
|
||||||
command = [
|
command = [
|
||||||
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
|
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
|
||||||
"-runs=100000",
|
"-runs=100000",
|
||||||
target_corpus_dir,
|
target_corpus_dir,
|
||||||
]
|
]
|
||||||
futures.append(fuzz_pool.submit(job, command, target))
|
futures.append(fuzz_pool.submit(job, command, target, t_env))
|
||||||
|
|
||||||
for future in as_completed(futures):
|
for future in as_completed(futures):
|
||||||
future.result()
|
future.result()
|
||||||
|
Loading…
Reference in New Issue
Block a user