Looking at the output, it seems to indicate that the fuzz target ran twice:
0 46| |FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
1- 47| 2|{
2- 48| 2| SeedRandomStateForTest(SeedRand::ZEROS);
3- 49| 2| FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
4- 50| 2| SetMockTime(ConsumeTime(fuzzed_data_provider));
5+ 47| 1|{
6+ 48| 1| SeedRandomStateForTest(SeedRand::ZEROS);
7+ 49| 1| FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
8+ 50| 1| SetMockTime(ConsumeTime(fuzzed_data_provider));
9 51| |
Thus, it seems there are two options:
- There is a bug in the code here and two processes are started by the same thread for the same run-id (or some other bug)
- There is a bug in libFuzzer and the fuzz target is run twice in the same process (most likely)
If you want to check this further, and if you want to check if the fuzz process itself is at fault, it should be possible by aborting it, if the process runs the target twice. (Also, could mock out the meat of the logic here):
0diff --git a/contrib/devtools/deterministic-fuzz-coverage/src/main.rs b/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
1index 9c1738396b..d5b7181c80 100644
2--- a/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
3+++ b/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
4@@ -150,40 +150,6 @@ fn deterministic_coverage(
5 ))?;
6 }
7 }
8- if !Command::new(LLVM_PROFDATA)
9- .arg("merge")
10- .arg("--sparse")
11- .arg(&profraw_file)
12- .arg("-o")
13- .arg(&profdata_file)
14- .status()
15- .map_err(|e| format!("{LLVM_PROFDATA} merge failed with {e}"))?
16- .success()
17- {
18- Err(format!("{LLVM_PROFDATA} merge failed. This can be a sign of compiling without code coverage support."))?;
19- }
20- let cov_file = File::create(&cov_txt_path)
21- .map_err(|e| format!("Failed to create coverage txt file ({e})"))?;
22- if !Command::new(LLVM_COV)
23- .args([
24- "show",
25- "--show-line-counts-or-regions",
26- "--show-branches=count",
27- "--show-expansions",
28- "--show-instantiation-summary",
29- "-Xdemangler=llvm-cxxfilt",
30- &format!("--instr-profile={}", profdata_file.display()),
31- ])
32- .arg(fuzz_exe)
33- .stdout(cov_file)
34- .spawn()
35- .map_err(|e| format!("{LLVM_COV} show failed with {e}"))?
36- .wait()
37- .map_err(|e| format!("{LLVM_COV} show failed with {e}"))?
38- .success()
39- {
40- Err(format!("{LLVM_COV} show failed"))?;
41- };
42 Ok(cov_txt_path)
43 };
44 let check_diff = |a: &Path, b: &Path, err: &str| -> AppResult {
45@@ -221,11 +187,6 @@ The coverage was not deterministic between runs.
46 }
47 let cov_txt_base = run_single('a', &entry, thread_id)?;
48 let cov_txt_repeat = run_single('b', &entry, thread_id)?;
49- check_diff(
50- &cov_txt_base,
51- &cov_txt_repeat,
52- &format!("The fuzz target input was {}.", entry.display()),
53- )?;
54 Ok(())
55 };
56 thread::scope(|s| -> AppResult {
57@@ -254,18 +215,6 @@ The coverage was not deterministic between runs.
58 // This can catch issues where mutable global state is leaked from one fuzz input execution to
59 // the next.
60 println!("Check all fuzz inputs in one go ...");
61- {
62- if !corpus_dir.is_dir() {
63- Err(format!("{} should be a folder", corpus_dir.display()))?;
64- }
65- let cov_txt_base = run_single('a', &corpus_dir, 0)?;
66- let cov_txt_repeat = run_single('b', &corpus_dir, 0)?;
67- check_diff(
68- &cov_txt_base,
69- &cov_txt_repeat,
70- &format!("All fuzz inputs in {} were used.", corpus_dir.display()),
71- )?;
72- }
73 println!("✨ Coverage test passed for {fuzz_target}. ✨");
74 Ok(())
75 }
76diff --git a/src/test/fuzz/partially_downloaded_block.cpp b/src/test/fuzz/partially_downloaded_block.cpp
77index 8c6565e48b..466548ee35 100644
78--- a/src/test/fuzz/partially_downloaded_block.cpp
79+++ b/src/test/fuzz/partially_downloaded_block.cpp
80@@ -45,6 +45,9 @@ PartiallyDownloadedBlock::CheckBlockFn FuzzedCheckBlock(std::optional<BlockValid
81
82 FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
83 {
84+static bool g_once{true};
85+Assert(g_once);
86+g_once=false;
87 SeedRandomStateForTest(SeedRand::ZEROS);
88 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
89 SetMockTime(ConsumeTime(fuzzed_data_provider));