LCOV - code coverage report
Current view: top level - src/test/util - poolresourcetester.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 0 44 0.0 %
Date: 2023-09-26 12:08:55 Functions: 0 10 0.0 %

          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             : #ifndef BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
       6             : #define BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
       7             : 
       8             : #include <support/allocators/pool.h>
       9             : 
      10             : #include <algorithm>
      11             : #include <cassert>
      12             : #include <cstddef>
      13             : #include <cstdint>
      14             : #include <vector>
      15             : 
      16             : /**
      17             :  * Helper to get access to private parts of PoolResource. Used in unit tests and in the fuzzer
      18             :  */
      19             : class PoolResourceTester
      20             : {
      21             :     struct PtrAndBytes {
      22             :         uintptr_t ptr;
      23             :         std::size_t size;
      24             : 
      25           0 :         PtrAndBytes(const void* p, std::size_t s)
      26           0 :             : ptr(reinterpret_cast<uintptr_t>(p)), size(s)
      27             :         {
      28           0 :         }
      29             : 
      30             :         /**
      31             :          * defines a sort ordering by the pointer value
      32             :          */
      33           0 :         friend bool operator<(PtrAndBytes const& a, PtrAndBytes const& b)
      34             :         {
      35           0 :             return a.ptr < b.ptr;
      36             :         }
      37             :     };
      38             : 
      39             : public:
      40             :     /**
      41             :      * Extracts the number of elements per freelist
      42             :      */
      43             :     template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
      44             :     static std::vector<std::size_t> FreeListSizes(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
      45             :     {
      46             :         auto sizes = std::vector<std::size_t>();
      47             :         for (const auto* ptr : resource.m_free_lists) {
      48             :             size_t size = 0;
      49             :             while (ptr != nullptr) {
      50             :                 ++size;
      51             :                 ptr = ptr->m_next;
      52             :             }
      53             :             sizes.push_back(size);
      54             :         }
      55             :         return sizes;
      56             :     }
      57             : 
      58             :     /**
      59             :      * How many bytes are still available from the last allocated chunk
      60             :      */
      61             :     template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
      62             :     static std::size_t AvailableMemoryFromChunk(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
      63             :     {
      64             :         return resource.m_available_memory_end - resource.m_available_memory_it;
      65             :     }
      66             : 
      67             :     /**
      68             :      * Once all blocks are given back to the resource, tests that the freelists are consistent:
      69             :      *
      70             :      * * All data in the freelists must come from the chunks
      71             :      * * Memory doesn't overlap
      72             :      * * Each byte in the chunks can be accounted for in either the freelist or as available bytes.
      73             :      */
      74             :     template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
      75           0 :     static void CheckAllDataAccountedFor(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
      76             :     {
      77             :         // collect all free blocks by iterating all freelists
      78           0 :         std::vector<PtrAndBytes> free_blocks;
      79           0 :         for (std::size_t freelist_idx = 0; freelist_idx < resource.m_free_lists.size(); ++freelist_idx) {
      80           0 :             std::size_t bytes = freelist_idx * resource.ELEM_ALIGN_BYTES;
      81           0 :             auto* ptr = resource.m_free_lists[freelist_idx];
      82           0 :             while (ptr != nullptr) {
      83           0 :                 free_blocks.emplace_back(ptr, bytes);
      84           0 :                 ptr = ptr->m_next;
      85             :             }
      86           0 :         }
      87             :         // also add whatever has not yet been used for blocks
      88           0 :         auto num_available_bytes = resource.m_available_memory_end - resource.m_available_memory_it;
      89           0 :         if (num_available_bytes > 0) {
      90           0 :             free_blocks.emplace_back(resource.m_available_memory_it, num_available_bytes);
      91           0 :         }
      92             : 
      93             :         // collect all chunks
      94           0 :         std::vector<PtrAndBytes> chunks;
      95           0 :         for (const std::byte* ptr : resource.m_allocated_chunks) {
      96           0 :             chunks.emplace_back(ptr, resource.ChunkSizeBytes());
      97             :         }
      98             : 
      99             :         // now we have all the data from all freelists on the one hand side, and all chunks on the other hand side.
     100             :         // To check if all of them match, sort by address and iterate.
     101           0 :         std::sort(free_blocks.begin(), free_blocks.end());
     102           0 :         std::sort(chunks.begin(), chunks.end());
     103             : 
     104           0 :         auto chunk_it = chunks.begin();
     105           0 :         auto chunk_ptr_remaining = chunk_it->ptr;
     106           0 :         auto chunk_size_remaining = chunk_it->size;
     107           0 :         for (const auto& free_block : free_blocks) {
     108           0 :             if (chunk_size_remaining == 0) {
     109           0 :                 assert(chunk_it != chunks.end());
     110           0 :                 ++chunk_it;
     111           0 :                 assert(chunk_it != chunks.end());
     112           0 :                 chunk_ptr_remaining = chunk_it->ptr;
     113           0 :                 chunk_size_remaining = chunk_it->size;
     114           0 :             }
     115           0 :             assert(free_block.ptr == chunk_ptr_remaining);                   // ensure addresses match
     116           0 :             assert(free_block.size <= chunk_size_remaining);                 // ensure no overflow
     117           0 :             assert((free_block.ptr & (resource.ELEM_ALIGN_BYTES - 1)) == 0); // ensure correct alignment
     118           0 :             chunk_ptr_remaining += free_block.size;
     119           0 :             chunk_size_remaining -= free_block.size;
     120             :         }
     121             :         // ensure we are at the end of the chunks
     122           0 :         assert(chunk_ptr_remaining == chunk_it->ptr + chunk_it->size);
     123           0 :         ++chunk_it;
     124           0 :         assert(chunk_it == chunks.end());
     125           0 :         assert(chunk_size_remaining == 0);
     126           0 :     }
     127             : };
     128             : 
     129             : #endif // BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H

Generated by: LCOV version 1.14