LCOV - code coverage report
Current view: top level - src/ipc/test/fuzz - ipc.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 49.4 % 83 41
Test Date: 2026-07-11 06:27:17 Functions: 53.3 % 15 8
Branches: 27.3 % 128 35

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2026-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <primitives/transaction.h>
       6                 :             : #include <capnp/capability.h>
       7                 :             : #include <capnp/rpc.h>
       8                 :             : #include <kj/memory.h>
       9                 :             : #include <mp/proxy-io.h>
      10                 :             : #include <mp/proxy.h>
      11                 :             : #include <test/fuzz/FuzzedDataProvider.h>
      12                 :             : #include <test/fuzz/fuzz.h>
      13                 :             : #include <ipc/test/fuzz/ipc_fuzz.capnp.h>
      14                 :             : #include <ipc/test/fuzz/ipc_fuzz.capnp.proxy.h>
      15                 :             : #include <ipc/test/fuzz/ipc_fuzz.h>
      16                 :             : #include <test/fuzz/util.h>
      17                 :             : #include <test/util/setup_common.h>
      18                 :             : 
      19                 :             : #include <future>
      20                 :             : #include <memory>
      21                 :             : #include <stdexcept>
      22                 :             : #include <thread>
      23                 :             : 
      24                 :             : namespace {
      25                 :             : class IpcFuzzSetup
      26                 :             : {
      27                 :             : public:
      28                 :           1 :     IpcFuzzSetup()
      29         [ +  - ]:           1 :     {
      30         [ +  - ]:           1 :         std::promise<std::unique_ptr<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>>> client_promise;
      31         [ +  - ]:           1 :         auto client_future{client_promise.get_future()};
      32                 :           1 :         m_loop_thread = std::thread([&client_promise] {
      33         [ +  - ]:           1 :             mp::EventLoop loop("ipc-fuzz", [](mp::LogMessage message) {
      34   [ -  +  -  - ]:          10 :                 if (message.level == mp::Log::Raise) throw std::runtime_error(message.message);
      35         [ +  - ]:          11 :             });
      36         [ +  - ]:           1 :             auto pipe = loop.m_io_context.provider->newTwoWayPipe();
      37                 :             : 
      38                 :           1 :             auto server_connection = std::make_unique<mp::Connection>(
      39                 :             :                 loop,
      40                 :             :                 kj::mv(pipe.ends[0]),
      41                 :           1 :                 [&](mp::Connection& connection) {
      42                 :           1 :                     auto server_proxy = kj::heap<mp::ProxyServer<test::fuzz::messages::IpcFuzzInterface>>(
      43         [ +  - ]:           1 :                         std::make_shared<IpcFuzzImplementation>(), connection);
      44   [ +  -  +  - ]:           1 :                     return capnp::Capability::Client(kj::mv(server_proxy));
      45         [ +  - ]:           2 :                 });
      46   [ +  -  +  - ]:           2 :             server_connection->onDisconnect([&] { server_connection.reset(); });
      47                 :             : 
      48         [ +  - ]:           1 :             auto client_connection = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]));
      49                 :           1 :             auto client_proxy = std::make_unique<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>>(
      50   [ +  -  +  -  :           1 :                 client_connection->m_rpc_system->bootstrap(mp::ServerVatId().vat_id)
                   +  - ]
      51         [ +  - ]:           1 :                     .castAs<test::fuzz::messages::IpcFuzzInterface>(),
      52         [ +  - ]:           1 :                 client_connection.get(),
      53   [ +  -  +  - ]:           2 :                 /* destroy_connection= */ true);
      54         [ +  - ]:           1 :             (void)client_connection.release();
      55                 :             : 
      56         [ +  - ]:           1 :             client_promise.set_value(std::move(client_proxy));
      57         [ +  - ]:           1 :             loop.loop();
      58   [ +  -  +  - ]:           2 :         });
      59   [ +  -  -  + ]:           1 :         m_client = client_future.get();
      60                 :           1 :     }
      61                 :             : 
      62                 :           1 :     ~IpcFuzzSetup()
      63                 :             :     {
      64         [ +  - ]:           1 :         m_client.reset();
      65         [ +  - ]:           1 :         if (m_loop_thread.joinable()) m_loop_thread.join();
      66                 :           1 :     }
      67                 :             : 
      68                 :             :     std::unique_ptr<mp::ProxyClient<test::fuzz::messages::IpcFuzzInterface>> m_client;
      69                 :             : 
      70                 :             : private:
      71                 :             :     std::thread m_loop_thread;
      72                 :             : };
      73                 :             : 
      74                 :             : static IpcFuzzSetup* g_ipc;
      75                 :             : 
      76                 :           1 : static void initialize_ipc()
      77                 :             : {
      78   [ +  -  +  -  :           1 :     static const auto testing_setup = MakeNoLogFileContext<>();
                   +  - ]
      79                 :           1 :     (void)testing_setup;
      80                 :             : 
      81                 :             :     // Ensure g_thread_context is destroyed after the IPC setup, since C++
      82                 :             :     // destroys thread_local objects in reverse construction order.
      83                 :           1 :     mp::ThreadContext& thread_context{mp::g_thread_context};
      84                 :           1 :     (void)thread_context;
      85                 :             : 
      86         [ +  - ]:           1 :     thread_local static IpcFuzzSetup ipc; // NOLINT(bitcoin-nontrivial-threadlocal)
      87                 :           1 :     g_ipc = &ipc;
      88                 :           1 : }
      89                 :             : 
      90         [ +  - ]:         472 : FUZZ_TARGET(ipc, .init = initialize_ipc)
      91                 :             : {
      92                 :           0 :     auto& ipc = *g_ipc;
      93                 :           0 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
      94                 :           0 :     const size_t iterations = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 64);
      95                 :             : 
      96         [ #  # ]:           0 :     for (size_t i = 0; i < iterations; ++i) {
      97                 :           0 :         CallOneOf(
      98                 :             :             fuzzed_data_provider,
      99                 :           0 :             [&] {
     100                 :           0 :                 static constexpr int MIN_ADD{-1'000'000};
     101                 :           0 :                 static constexpr int MAX_ADD{1'000'000};
     102                 :           0 :                 const int a = fuzzed_data_provider.ConsumeIntegralInRange<int>(MIN_ADD, MAX_ADD);
     103                 :           0 :                 const int b = fuzzed_data_provider.ConsumeIntegralInRange<int>(MIN_ADD, MAX_ADD);
     104         [ #  # ]:           0 :                 assert(ipc.m_client->add(a, b) == a + b);
     105                 :           0 :             },
     106                 :           0 :             [&] {
     107                 :           0 :                 COutPoint outpoint{Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider)),
     108                 :           0 :                                    fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
     109                 :           0 :                 COutPoint expected{outpoint.hash, outpoint.n ^ 0xFFFFFFFFu};
     110         [ #  # ]:           0 :                 assert(ipc.m_client->passOutPoint(outpoint) == expected);
     111                 :           0 :             },
     112                 :           0 :             [&] {
     113                 :           0 :                 std::vector<uint8_t> value = ConsumeRandomLengthByteVector<uint8_t>(fuzzed_data_provider, 512);
     114                 :             :                 // Empty Data currently trips UBSan in the libmultiprocess byte-span serializer.
     115   [ #  #  #  # ]:           0 :                 if (value.empty()) value.push_back(0);
     116         [ #  # ]:           0 :                 std::vector<uint8_t> expected{value.rbegin(), value.rend()};
     117   [ #  #  #  #  :           0 :                 assert(ipc.m_client->passVectorUint8(value) == expected);
                   #  # ]
     118                 :           0 :             },
     119                 :           0 :             [&] {
     120                 :           0 :                 CScript script{ConsumeScript(fuzzed_data_provider)};
     121                 :           0 :                 CScript expected{script};
     122         [ #  # ]:           0 :                 expected << OP_NOP;
     123   [ #  #  #  # ]:           0 :                 assert(ipc.m_client->passScript(script) == expected);
     124                 :           0 :             },
     125                 :           0 :             [&] {
     126         [ #  # ]:           0 :                 UniValue value;
     127   [ #  #  #  #  :           0 :                 if (!value.read(fuzzed_data_provider.ConsumeRandomLengthString(512))) return;
                   #  # ]
     128   [ #  #  #  #  :           0 :                 assert(ipc.m_client->passUniValue(value).write() == value.write());
          #  #  #  #  #  
                      # ]
     129                 :           0 :             },
     130                 :           0 :             [&] {
     131                 :           0 :                 const CMutableTransaction mutable_tx = ConsumeTransaction(fuzzed_data_provider, std::nullopt);
     132         [ #  # ]:           0 :                 if (mutable_tx.vin.empty()) return;
     133         [ #  # ]:           0 :                 const CTransactionRef tx = MakeTransactionRef(mutable_tx);
     134   [ #  #  #  #  :           0 :                 assert(*ipc.m_client->passTransaction(tx) == *tx);
          #  #  #  #  #  
                      # ]
     135                 :           0 :             });
     136                 :             :     }
     137                 :           0 : }
     138                 :             : } // namespace
        

Generated by: LCOV version 2.0-1