Coverage Report

Created: 2025-02-21 14:37

/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