fuzz: add ipc round-trip fuzz target #35118

pull enirox001 wants to merge 2 commits into bitcoin:master from enirox001:fuzz-ipc-initial changing 6 files +281 −1
  1. enirox001 commented at 8:30 AM on April 20, 2026: contributor

    <!-- *** Please remove the following help text before submitting: *** Pull requests without a rationale and clear improvement may be closed immediately. GUI-related pull requests should be opened against https://github.com/bitcoin-core/gui first. See CONTRIBUTING.md -->

    <!-- Please provide clear motivation for your patch and explain how it improves Bitcoin Core user experience or Bitcoin Core developer experience significantly: * Any test improvements or new tests that improve coverage are always welcome. * All other changes should have accompanying unit tests (see `src/test/`) or functional tests (see `test/`). Contributors should note which tests cover modified code. If no tests exist for a region of modified code, new tests should accompany the change. * Bug fixes are most welcome when they come with steps to reproduce or an explanation of the potential issue as well as reasoning for the way the bug was fixed. * Features are welcome, but might be rejected due to design or scope issues. If a feature is based on a lot of dependencies, contributors should first consider building the system outside of Bitcoin Core, if possible. * Refactoring changes are only accepted if they are required for a feature or bug fix or otherwise improve developer experience significantly. For example, most "code style" refactoring changes require a thorough explanation why they are useful, what downsides they have and why they *significantly* improve developer experience or avoid serious programming bugs. Note that code style is often a subjective matter. Unless they are explicitly mentioned to be preferred in the [developer notes](/doc/developer-notes.md), stylistic code changes are usually rejected. -->

    <!-- Bitcoin Core has a thorough review process and even the most trivial change needs to pass a lot of eyes and requires non-zero or even substantial time effort to review. There is a huge lack of active reviewers on the project, so patches often sit for a long time. -->

    As discussed in #23015, this PR adds an IPC fuzz target to exercise the Cap'n Proto/libmultiprocess serialization bridge using an in-process two-way pipe and a reflected test interface.

    It covers round-trip serialization for COutPoint, CScript, std::vector<uint8_t>, UniValue, and transactions, and exercises libmultiprocess proxy/server interaction. The target guarantees at least one IPC operation per input and is included by default when IPC is enabled in fuzz builds

  2. DrahtBot added the label Fuzzing on Apr 20, 2026
  3. DrahtBot commented at 8:31 AM on April 20, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35118.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    No conflicts as of last run.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. enirox001 force-pushed on Apr 20, 2026
  5. DrahtBot added the label CI failed on Apr 20, 2026
  6. enirox001 force-pushed on Apr 20, 2026
  7. enirox001 force-pushed on Apr 20, 2026
  8. DrahtBot removed the label CI failed on Apr 20, 2026
  9. ViniciusCestarii commented at 6:37 PM on April 20, 2026: contributor

    While testing this PR with cmake --preset=libfuzzer, I noticed the new ipc target never makes it into the fuzz binary (FUZZ=ipc build_fuzz/bin/fuzz reports No fuzz target compiled for ipc).

    The cause is in the top-level CMakeLists.txt:234: when BUILD_FOR_FUZZING=ON, ENABLE_IPC is unconditionally forced OFF, which makes the if(ENABLE_IPC) guard in src/test/fuzz/CMakeLists.txt skip ipc.cpp. So the target added by this PR can't actually be exercised through the standard fuzz preset.

    I believe the fix is to drop set(ENABLE_IPC OFF) from CMakeLists.txt:234.

  10. ViniciusCestarii commented at 7:42 PM on April 20, 2026: contributor

    Three of the four methods (passOutPoint, passVectorUint8, passScript) are identity round-trips. add(a, b) is stronger because the server has to actually decode a and b to compute the sum and the client then checks against the original inputs.

    With identity, the server never has to understand the value it received, so a broken deserialization can be re-serialized as the same garbage and still compare equal. A small deterministic transform on the server side would close that gap, e.g.:

      std::vector<uint8_t> passVectorUint8(std::vector<uint8_t> v) {
          std::reverse(v.begin(), v.end());
          return v;
      }
      CScript passScript(CScript s) { s << OP_NOP; return s; }
      COutPoint passOutPoint(COutPoint o) { return COutPoint{o.hash, o.n ^ 0xFFFFFFFFu}; }
    

    and then comparing against the reproduced transform on the client just like add(a, b). This matches the "transform, reverse, or shift" idea from #23015.

  11. enirox001 force-pushed on Apr 21, 2026
  12. enirox001 force-pushed on Apr 21, 2026
  13. DrahtBot added the label CI failed on Apr 21, 2026
  14. DrahtBot commented at 3:58 AM on April 21, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task lint: https://github.com/bitcoin/bitcoin/actions/runs/24702970550/job/72250002067</sub> <sub>LLM reason (✨ experimental): CI failed due to a lint error for trailing whitespace detected by the trailing_whitespace check.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  15. enirox001 force-pushed on Apr 21, 2026
  16. enirox001 force-pushed on Apr 21, 2026
  17. enirox001 commented at 4:43 AM on April 21, 2026: contributor

    Thanks for the review @ViniciusCestarii

    While testing this PR with cmake --preset=libfuzzer, I noticed the new ipc target never makes it into the fuzz binary (FUZZ=ipc build_fuzz/bin/fuzz reports No fuzz target compiled for ipc). I believe the fix is to drop set(ENABLE_IPC OFF) from CMakeLists.txt:234.

    The fix is indeed to remove set(ENABLE_IPC OFF) from the BUILD_FOR_FUZZING block, that line was added in af4156ab to work around missing capnp in fuzzing builds, but since add_libmultiprocess and add_subdirectory(ipc) are both gated behind ENABLE_IPC in src/CMakeLists.txt, users without capnp will still get ENABLE_IPC=OFF naturally with no configure error.

    With identity, the server never has to understand the value it received, so a broken deserialization can be re-serialized as the same garbage and still compare equal. A small deterministic transform on the server side would close that gap, e.g.:

      std::vector<uint8_t> passVectorUint8(std::vector<uint8_t> v) {
          std::reverse(v.begin(), v.end());
          return v;
      }
      CScript passScript(CScript s) { s << OP_NOP; return s; }
      COutPoint passOutPoint(COutPoint o) { return COutPoint{o.hash, o.n ^ 0xFFFFFFFFu}; }
    

    and then comparing against the reproduced transform on the client just like add(a, b). This matches the "transform, reverse, or shift" idea from #23015.

    Good point. Updated the three identity methods to use deterministic transforms instead:

    • passOutPoint: XORs n with 0xFFFFFFFF
    • passVectorUint8: reverses the vector
    • passScript: appends OP_NOP

    The client-side asserts now reproduce the same transform and compare against that

  18. enirox001 force-pushed on Apr 21, 2026
  19. enirox001 force-pushed on Apr 21, 2026
  20. enirox001 force-pushed on Apr 21, 2026
  21. enirox001 force-pushed on Apr 21, 2026
  22. DrahtBot removed the label CI failed on Apr 21, 2026
  23. enirox001 renamed this:
    fuzz: Add IPC round-trip fuzz target
    fuzz: add ipc round-trip fuzz target
    on Apr 23, 2026
  24. enirox001 force-pushed on Apr 23, 2026
  25. enirox001 commented at 9:22 AM on April 23, 2026: contributor

    Updated the branch to keep the IPC fuzz target opt-in instead of enabling IPC for all fuzz builds.

    The issue was that BUILD_FOR_FUZZING=ON intentionally disables IPC, so the new ipc target was not compiled even when using the standard libFuzzer preset. Simply dropping set(ENABLE_IPC OFF) would make cmake --preset=libfuzzer require IPC/libmultiprocess dependencies by default, which seems unnecessarily disruptive for existing fuzz builds.

    The current approach preserves the existing default behavior:

    • cmake --preset=libfuzzer keeps IPC disabled.
    • cmake --preset=libfuzzer -DENABLE_IPC=ON builds the IPC fuzz target.

    I also removed the unrelated fuzz target linking cleanup from this PR. The remaining diff is focused on making IPC fuzzing explicitly buildable and adding the initial ipc round-trip target.

  26. enirox001 force-pushed on Apr 23, 2026
  27. DrahtBot added the label CI failed on Apr 23, 2026
  28. DrahtBot commented at 9:33 AM on April 23, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task 32 bit ARM: https://github.com/bitcoin/bitcoin/actions/runs/24827161441/job/72666022727</sub> <sub>LLM reason (✨ experimental): CI failed because the fuzz target build stopped with a missing include file (mp/proxy.capnp.h) causing a fatal compilation error.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  29. enirox001 force-pushed on Apr 24, 2026
  30. DrahtBot removed the label CI failed on Apr 24, 2026
  31. sedited requested review from marcofleon on Apr 24, 2026
  32. ViniciusCestarii commented at 12:39 PM on April 29, 2026: contributor
    • cmake --preset=libfuzzer keeps IPC disabled.
    • cmake --preset=libfuzzer -DENABLE_IPC=ON builds the IPC fuzz target.

    I don't believe this is the correct approach. The preset libfuzzer is a preset to build everything necessary to run all fuzz targets and not partially. This way it can silently skips coverage, which is confusing and sets a precedent where every future subsystem fuzzer becomes another flag to remember.

  33. build: allow ipc fuzz builds
    Do not force ENABLE_IPC=OFF when BUILD_FOR_FUZZING is enabled.
    
    The libfuzzer preset is expected to build the full fuzz surface, and the
    ipc target should not require an extra opt-in flag to be compiled.
    
    IPC already depends on the normal top-level ENABLE_IPC option and will fail
    naturally when its Capn Proto dependencies are unavailable. Keeping the
    fuzz-only override would silently skip IPC coverage in standard fuzz builds.
    8a739a5510
  34. enirox001 force-pushed on Apr 30, 2026
  35. enirox001 commented at 8:03 AM on April 30, 2026: contributor

    I don't believe this is the correct approach. The preset libfuzzer is a preset to build everything necessary to run all fuzz targets and not partially. This way it can silently skips coverage, which is confusing and sets a precedent where every future subsystem fuzzer becomes another flag to remember.

    Looking at this again, you are correct.

    My earlier rationale was to keep cmake --preset=libfuzzer from pulling in IPC by default, and require -DENABLE_IPC=ON to opt into this target.

    But that seems to be the wrong tradeoff here, because it makes the libfuzzer preset silently build only a partial fuzz surface. IPC is already governed by the normal top-level ENABLE_IPC option, so treating fuzz builds specially in this case does not seem justified.

    I updated the branch to remove the fuzz-only ENABLE_IPC=OFF override. With this change, cmake --preset=libfuzzer follows the normal ENABLE_IPC behavior and includes the IPC fuzz target by default when IPC is enabled for the build.

    Also updated the PR description to match changes made

  36. enirox001 force-pushed on Apr 30, 2026
  37. DrahtBot added the label CI failed on Apr 30, 2026
  38. DrahtBot commented at 8:36 AM on April 30, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task fuzzer,address,undefined,integer: https://github.com/bitcoin/bitcoin/actions/runs/25154022524/job/73731223345</sub> <sub>LLM reason (✨ experimental): Fuzz testing crashed under AddressSanitizer (memory corruption) causing the CI job to abort with exit code 1.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  39. enirox001 force-pushed on Apr 30, 2026
  40. enirox001 commented at 9:13 AM on April 30, 2026: contributor

    Updated the harness after sanitizer failures in the direct-call version.

    IPC client calls are now routed through a dedicated worker thread so libmultiprocess thread-local client state is not initialized on the main fuzzing thread. This avoids teardown-time sanitizer failures without changing the target's intended IPC coverage.

  41. DrahtBot removed the label CI failed on Apr 30, 2026
  42. enirox001 force-pushed on May 4, 2026
  43. DrahtBot added the label CI failed on May 4, 2026
  44. DrahtBot commented at 5:39 PM on May 4, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task i686, no IPC: https://github.com/bitcoin/bitcoin/actions/runs/25330582475/job/74262991276</sub> <sub>LLM reason (✨ experimental): CI failed because the sock_tests CTest module hit fatal socket errors (critical check s != (SOCKET)-1 has failed), causing 6 test failures.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  45. enirox001 force-pushed on May 4, 2026
  46. enirox001 force-pushed on May 5, 2026
  47. enirox001 force-pushed on May 5, 2026
  48. enirox001 force-pushed on May 5, 2026
  49. enirox001 force-pushed on May 5, 2026
  50. DrahtBot removed the label CI failed on May 5, 2026
  51. fuzz: add IPC round-trip target
    Add an ipc fuzz target behind ENABLE_IPC.
    
    The target sets up an in-process two-way pipe and exercises the IPC bridge by round-tripping a small reflected interface over libmultiprocess. Cover COutPoint, CScript, std::vector<uint8_t>, UniValue, and transactions.
    
    Keep the harness alive across iterations and ensure each input performs at least one IPC call.
    9ac410a662
  52. enirox001 force-pushed on May 5, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-12 15:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me