/
githubmirror
/
bitcoin
Обзор
Документация
Войти
/
githubmirror
/
bitcoin
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/test/util/poolresourcetester.h
136 строк
5 KB
MarcoFalke
scripted-diff: [doc] Unify stale copyright headers
17 дек 2025, 00:21
17 дек 2025, 00:21
fa5f297
Код
Авторство
О чём код?
// Copyright (c) 2022-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H #define BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H #include <support/allocators/pool.h> #include <util/check.h> #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> #include <vector> /** * Helper to get access to private parts of PoolResource. Used in unit tests and in the fuzzer */ class PoolResourceTester { struct PtrAndBytes { uintptr_t ptr; std::size_t size; PtrAndBytes(const void* p, std::size_t s) : ptr(reinterpret_cast<uintptr_t>(p)), size(s) { } /** * defines a sort ordering by the pointer value */ friend bool operator<(PtrAndBytes const& a, PtrAndBytes const& b) { return a.ptr < b.ptr; } }; public: /** * Extracts the number of elements per freelist */ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES> static std::vector<std::size_t> FreeListSizes(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource) { auto sizes = std::vector<std::size_t>(); for (const auto* ptr : resource.m_free_lists) { size_t size = 0; while (ptr != nullptr) { ++size; const auto* ptr_ = ptr; ASAN_UNPOISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode)); ptr = ptr->m_next; ASAN_POISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode)); } sizes.push_back(size); } return sizes; } /** * How many bytes are still available from the last allocated chunk */ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES> static std::size_t AvailableMemoryFromChunk(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource) { return resource.m_available_memory_end - resource.m_available_memory_it; } /** * Once all blocks are given back to the resource, tests that the freelists are consistent: * * * All data in the freelists must come from the chunks * * Memory doesn't overlap * * Each byte in the chunks can be accounted for in either the freelist or as available bytes. */ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES> static void CheckAllDataAccountedFor(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource) { // collect all free blocks by iterating all freelists std::vector<PtrAndBytes> free_blocks; for (std::size_t freelist_idx = 0; freelist_idx < resource.m_free_lists.size(); ++freelist_idx) { std::size_t bytes = freelist_idx * resource.ELEM_ALIGN_BYTES; auto* ptr = resource.m_free_lists[freelist_idx]; while (ptr != nullptr) { free_blocks.emplace_back(ptr, bytes); const auto* ptr_ = ptr; ASAN_UNPOISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode)); ptr = ptr->m_next; ASAN_POISON_MEMORY_REGION(ptr_, sizeof(typename PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>::ListNode)); } } // also add whatever has not yet been used for blocks auto num_available_bytes = resource.m_available_memory_end - resource.m_available_memory_it; if (num_available_bytes > 0) { free_blocks.emplace_back(resource.m_available_memory_it, num_available_bytes); } // collect all chunks std::vector<PtrAndBytes> chunks; for (const std::byte* ptr : resource.m_allocated_chunks) { chunks.emplace_back(ptr, resource.ChunkSizeBytes()); } // now we have all the data from all freelists on the one hand side, and all chunks on the other hand side. // To check if all of them match, sort by address and iterate. std::sort(free_blocks.begin(), free_blocks.end()); std::sort(chunks.begin(), chunks.end()); auto chunk_it = chunks.begin(); auto chunk_ptr_remaining = chunk_it->ptr; auto chunk_size_remaining = chunk_it->size; for (const auto& free_block : free_blocks) { if (chunk_size_remaining == 0) { assert(chunk_it != chunks.end()); ++chunk_it; assert(chunk_it != chunks.end()); chunk_ptr_remaining = chunk_it->ptr; chunk_size_remaining = chunk_it->size; } assert(free_block.ptr == chunk_ptr_remaining); // ensure addresses match assert(free_block.size <= chunk_size_remaining); // ensure no overflow assert((free_block.ptr & (resource.ELEM_ALIGN_BYTES - 1)) == 0); // ensure correct alignment chunk_ptr_remaining += free_block.size; chunk_size_remaining -= free_block.size; } // ensure we are at the end of the chunks assert(chunk_ptr_remaining == chunk_it->ptr + chunk_it->size); ++chunk_it; assert(chunk_it == chunks.end()); assert(chunk_size_remaining == 0); } }; #endif // BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H