Skip to content

Commit 04718ab

Browse files
fanquakevijaydasmp
authored andcommitted
Merge bitcoin#28015: fuzz: Generate rpc fuzz targets individually
fa1e27f fuzz: Generate rpc fuzz targets individually (MarcoFalke) Pull request description: The `rpc` fuzz target was added more than two years ago in e458631. However, the bug bitcoin#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: ACK fa1e27f dergoegge: ACK fa1e27f Tree-SHA512: 45ccba842367650d010320603153276b1b303deda9ba8c6bb31a4d2473b00aa5bca866db95f541485d65efd8276e2575026968c037872ef344fa33cf45bcdcd7
1 parent ce4f2a3 commit 04718ab

1 file changed

Lines changed: 26 additions & 8 deletions

File tree

test/fuzz/test_runner.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,22 +203,40 @@ def generate_corpus(*, fuzz_pool, src_dir, fuzz_bin, corpus_dir, targets):
203203
{corpus_dir}.
204204
"""
205205
logging.info("Generating corpus to {}".format(corpus_dir))
206+
rpc_target = "rpc"
207+
has_rpc = rpc_target in targets
208+
if has_rpc:
209+
targets.remove(rpc_target)
210+
targets = [(t, {}) for t in targets]
211+
if has_rpc:
212+
lines = subprocess.run(
213+
["git", "grep", "--function-context", "RPC_COMMANDS_SAFE_FOR_FUZZING{", os.path.join(src_dir, "src", "test", "fuzz", "rpc.cpp")],
214+
check=True,
215+
stdout=subprocess.PIPE,
216+
text=True,
217+
).stdout.splitlines()
218+
lines = [l.split("\"", 1)[1].split("\"")[0] for l in lines if l.startswith("src/test/fuzz/rpc.cpp- \"")]
219+
targets += [(rpc_target, {"LIMIT_TO_RPC_COMMAND": r}) for r in lines]
206220

207-
def job(command, t):
208-
logging.debug("Running '{}'\n".format(" ".join(command)))
221+
def job(command, t, t_env):
222+
logging.debug(f"Running '{command}'")
209223
logging.debug("Command '{}' output:\n'{}'\n".format(
210-
' '.join(command),
224+
command,
211225
subprocess.run(
212226
command,
213-
env=get_fuzz_env(target=t, source_dir=src_dir),
227+
env={
228+
**t_env,
229+
**get_fuzz_env(target=t, source_dir=src_dir),
230+
},
214231
check=True,
215232
stderr=subprocess.PIPE,
216233
text=True,
217-
).stderr))
234+
).stderr,
235+
))
218236

219237
futures = []
220-
for target in targets:
221-
target_corpus_dir = os.path.join(corpus_dir, target)
238+
for target, t_env in targets:
239+
target_corpus_dir = corpus_dir / target
222240
os.makedirs(target_corpus_dir, exist_ok=True)
223241
use_value_profile = int(random.random() < .3)
224242
command = [
@@ -229,7 +247,7 @@ def job(command, t):
229247
f"-use_value_profile={use_value_profile}",
230248
target_corpus_dir,
231249
]
232-
futures.append(fuzz_pool.submit(job, command, target))
250+
futures.append(fuzz_pool.submit(job, command, target, t_env))
233251

234252
for future in as_completed(futures):
235253
future.result()

0 commit comments

Comments
 (0)