LCOV - code coverage report
Current view: top level - src/test/fuzz - poolresource.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 2 100 2.0 %
Date: 2023-09-26 12:08:55 Functions: 2 115 1.7 %

          Line data    Source code
       1             : // Copyright (c) 2022 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 <span.h>
       6             : #include <support/allocators/pool.h>
       7             : #include <test/fuzz/FuzzedDataProvider.h>
       8             : #include <test/fuzz/fuzz.h>
       9             : #include <test/fuzz/util.h>
      10             : #include <test/util/poolresourcetester.h>
      11             : #include <test/util/xoroshiro128plusplus.h>
      12             : 
      13             : #include <cstdint>
      14             : #include <tuple>
      15             : #include <vector>
      16             : 
      17             : namespace {
      18             : 
      19             : template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
      20             : class PoolResourceFuzzer
      21             : {
      22             :     FuzzedDataProvider& m_provider;
      23             :     PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES> m_test_resource;
      24           0 :     uint64_t m_sequence{0};
      25           2 :     size_t m_total_allocated{};
      26             : 
      27             :     struct Entry {
      28             :         Span<std::byte> span;
      29             :         size_t alignment;
      30             :         uint64_t seed;
      31             : 
      32           0 :         Entry(Span<std::byte> s, size_t a, uint64_t se) : span(s), alignment(a), seed(se) {}
      33             :     };
      34             : 
      35             :     std::vector<Entry> m_entries;
      36             : 
      37             : public:
      38           0 :     PoolResourceFuzzer(FuzzedDataProvider& provider)
      39           0 :         : m_provider{provider},
      40           0 :           m_test_resource{provider.ConsumeIntegralInRange<size_t>(MAX_BLOCK_SIZE_BYTES, 262144)}
      41             :     {
      42           0 :     }
      43             : 
      44           0 :     void Allocate(size_t size, size_t alignment)
      45             :     {
      46           0 :         assert(size > 0);                           // Must allocate at least 1 byte.
      47           0 :         assert(alignment > 0);                      // Alignment must be at least 1.
      48           0 :         assert((alignment & (alignment - 1)) == 0); // Alignment must be power of 2.
      49           0 :         assert((size & (alignment - 1)) == 0);      // Size must be a multiple of alignment.
      50             : 
      51           0 :         auto span = Span(static_cast<std::byte*>(m_test_resource.Allocate(size, alignment)), size);
      52           0 :         m_total_allocated += size;
      53             : 
      54           0 :         auto ptr_val = reinterpret_cast<std::uintptr_t>(span.data());
      55           0 :         assert((ptr_val & (alignment - 1)) == 0);
      56             : 
      57           0 :         uint64_t seed = m_sequence++;
      58           0 :         RandomContentFill(m_entries.emplace_back(span, alignment, seed));
      59           0 :     }
      60             : 
      61             :     void
      62           0 :     Allocate()
      63             :     {
      64           0 :         if (m_total_allocated > 0x1000000) return;
      65           0 :         size_t alignment_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 7);
      66           0 :         size_t alignment = 1 << alignment_bits;
      67           0 :         size_t size_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 16 - alignment_bits);
      68           0 :         size_t size = m_provider.ConsumeIntegralInRange<size_t>(1U << size_bits, (1U << (size_bits + 1)) - 1U) << alignment_bits;
      69           0 :         Allocate(size, alignment);
      70           0 :     }
      71             : 
      72           0 :     void RandomContentFill(Entry& entry)
      73             :     {
      74           0 :         XoRoShiRo128PlusPlus rng(entry.seed);
      75           0 :         auto ptr = entry.span.data();
      76           0 :         auto size = entry.span.size();
      77             : 
      78           0 :         while (size >= 8) {
      79           0 :             auto r = rng();
      80           0 :             std::memcpy(ptr, &r, 8);
      81           0 :             size -= 8;
      82           0 :             ptr += 8;
      83             :         }
      84           0 :         if (size > 0) {
      85           0 :             auto r = rng();
      86           0 :             std::memcpy(ptr, &r, size);
      87           0 :         }
      88           0 :     }
      89             : 
      90           0 :     void RandomContentCheck(const Entry& entry)
      91             :     {
      92           0 :         XoRoShiRo128PlusPlus rng(entry.seed);
      93           0 :         auto ptr = entry.span.data();
      94           0 :         auto size = entry.span.size();
      95             : 
      96             :         std::byte buf[8];
      97           0 :         while (size >= 8) {
      98           0 :             auto r = rng();
      99           0 :             std::memcpy(buf, &r, 8);
     100           0 :             assert(std::memcmp(buf, ptr, 8) == 0);
     101           0 :             size -= 8;
     102           0 :             ptr += 8;
     103             :         }
     104           0 :         if (size > 0) {
     105           0 :             auto r = rng();
     106           0 :             std::memcpy(buf, &r, size);
     107           0 :             assert(std::memcmp(buf, ptr, size) == 0);
     108           0 :         }
     109           0 :     }
     110             : 
     111           0 :     void Deallocate(const Entry& entry)
     112             :     {
     113           0 :         auto ptr_val = reinterpret_cast<std::uintptr_t>(entry.span.data());
     114           0 :         assert((ptr_val & (entry.alignment - 1)) == 0);
     115           0 :         RandomContentCheck(entry);
     116           0 :         m_total_allocated -= entry.span.size();
     117           0 :         m_test_resource.Deallocate(entry.span.data(), entry.span.size(), entry.alignment);
     118           0 :     }
     119             : 
     120           0 :     void Deallocate()
     121             :     {
     122           0 :         if (m_entries.empty()) {
     123           0 :             return;
     124             :         }
     125             : 
     126           0 :         size_t idx = m_provider.ConsumeIntegralInRange<size_t>(0, m_entries.size() - 1);
     127           0 :         Deallocate(m_entries[idx]);
     128           0 :         if (idx != m_entries.size() - 1) {
     129           0 :             m_entries[idx] = std::move(m_entries.back());
     130           0 :         }
     131           0 :         m_entries.pop_back();
     132           0 :     }
     133             : 
     134           0 :     void Clear()
     135             :     {
     136           0 :         while (!m_entries.empty()) {
     137           0 :             Deallocate();
     138             :         }
     139             : 
     140           0 :         PoolResourceTester::CheckAllDataAccountedFor(m_test_resource);
     141           0 :     }
     142             : 
     143           0 :     void Fuzz()
     144             :     {
     145           0 :         LIMITED_WHILE(m_provider.ConsumeBool(), 10000)
     146             :         {
     147           0 :             CallOneOf(
     148           0 :                 m_provider,
     149           0 :                 [&] { Allocate(); },
     150           0 :                 [&] { Deallocate(); });
     151           0 :         }
     152           0 :         Clear();
     153           0 :     }
     154             : };
     155             : 
     156             : 
     157             : } // namespace
     158             : 
     159           4 : FUZZ_TARGET(pool_resource)
     160             : {
     161           0 :     FuzzedDataProvider provider(buffer.data(), buffer.size());
     162           0 :     CallOneOf(
     163             :         provider,
     164           0 :         [&] { PoolResourceFuzzer<128, 1>{provider}.Fuzz(); },
     165           0 :         [&] { PoolResourceFuzzer<128, 2>{provider}.Fuzz(); },
     166           0 :         [&] { PoolResourceFuzzer<128, 4>{provider}.Fuzz(); },
     167           0 :         [&] { PoolResourceFuzzer<128, 8>{provider}.Fuzz(); },
     168             : 
     169           0 :         [&] { PoolResourceFuzzer<8, 8>{provider}.Fuzz(); },
     170           0 :         [&] { PoolResourceFuzzer<16, 16>{provider}.Fuzz(); },
     171             : 
     172           0 :         [&] { PoolResourceFuzzer<256, alignof(max_align_t)>{provider}.Fuzz(); },
     173           0 :         [&] { PoolResourceFuzzer<256, 64>{provider}.Fuzz(); });
     174           0 : }

Generated by: LCOV version 1.14