/root/bitcoin/src/test/util/poolresourcetester.h
Line | Count | Source (jump to first uncovered line) |
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 | | PtrAndBytes(const void* p, std::size_t s) |
26 | 0 | : ptr(reinterpret_cast<uintptr_t>(p)), size(s) |
27 | 0 | { |
28 | 0 | } |
29 | | |
30 | | /** |
31 | | * defines a sort ordering by the pointer value |
32 | | */ |
33 | | friend bool operator<(PtrAndBytes const& a, PtrAndBytes const& b) |
34 | 0 | { |
35 | 0 | return a.ptr < b.ptr; |
36 | 0 | } |
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 | | static void CheckAllDataAccountedFor(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource) |
76 | 0 | { |
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 | 0 | } |
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 | 0 | } |
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 | 0 | } |
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 | } Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm128ELm1EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm128ELm2EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm128ELm4EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm128ELm8EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm8ELm8EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm16ELm16EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm256ELm16EEEvRK12PoolResourceIXT_EXT0_EE Unexecuted instantiation: _ZN18PoolResourceTester24CheckAllDataAccountedForILm256ELm64EEEvRK12PoolResourceIXT_EXT0_EE |
127 | | }; |
128 | | |
129 | | #endif // BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H |