LCOV - code coverage report
Current view: top level - src/test/fuzz - poolresource.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 2 102 2.0 %
Date: 2023-11-06 23:13:05 Functions: 1 115 0.9 %
Branches: 2 308 0.6 %

           Branch data     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                 :          0 : 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 [ +  - ][ +  - ]:          6 : 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