Bitcoin Core 28.99.0
P2P Digital Currency
poolresource.cpp
Go to the documentation of this file.
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 <random.h>
6#include <span.h>
9#include <test/fuzz/fuzz.h>
10#include <test/fuzz/util.h>
12
13#include <cstdint>
14#include <tuple>
15#include <vector>
16
17namespace {
18
19template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
20class PoolResourceFuzzer
21{
22 FuzzedDataProvider& m_provider;
24 uint64_t m_sequence{0};
25 size_t m_total_allocated{};
26
27 struct Entry {
28 Span<std::byte> span;
29 size_t alignment;
30 uint64_t seed;
31
32 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
37public:
38 PoolResourceFuzzer(FuzzedDataProvider& provider)
39 : m_provider{provider},
40 m_test_resource{provider.ConsumeIntegralInRange<size_t>(MAX_BLOCK_SIZE_BYTES, 262144)}
41 {
42 }
43
44 void Allocate(size_t size, size_t alignment)
45 {
46 assert(size > 0); // Must allocate at least 1 byte.
47 assert(alignment > 0); // Alignment must be at least 1.
48 assert((alignment & (alignment - 1)) == 0); // Alignment must be power of 2.
49 assert((size & (alignment - 1)) == 0); // Size must be a multiple of alignment.
50
51 auto span = Span(static_cast<std::byte*>(m_test_resource.Allocate(size, alignment)), size);
52 m_total_allocated += size;
53
54 auto ptr_val = reinterpret_cast<std::uintptr_t>(span.data());
55 assert((ptr_val & (alignment - 1)) == 0);
56
57 uint64_t seed = m_sequence++;
58 RandomContentFill(m_entries.emplace_back(span, alignment, seed));
59 }
60
61 void
62 Allocate()
63 {
64 if (m_total_allocated > 0x1000000) return;
65 size_t alignment_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 7);
66 size_t alignment = size_t{1} << alignment_bits;
67 size_t size_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 16 - alignment_bits);
68 size_t size = m_provider.ConsumeIntegralInRange<size_t>(size_t{1} << size_bits, (size_t{1} << (size_bits + 1)) - 1U) << alignment_bits;
69 Allocate(size, alignment);
70 }
71
72 void RandomContentFill(Entry& entry)
73 {
74 InsecureRandomContext(entry.seed).fillrand(entry.span);
75 }
76
77 void RandomContentCheck(const Entry& entry)
78 {
79 std::vector<std::byte> expect(entry.span.size());
81 assert(std::ranges::equal(entry.span, expect));
82 }
83
84 void Deallocate(const Entry& entry)
85 {
86 auto ptr_val = reinterpret_cast<std::uintptr_t>(entry.span.data());
87 assert((ptr_val & (entry.alignment - 1)) == 0);
88 RandomContentCheck(entry);
89 m_total_allocated -= entry.span.size();
90 m_test_resource.Deallocate(entry.span.data(), entry.span.size(), entry.alignment);
91 }
92
93 void Deallocate()
94 {
95 if (m_entries.empty()) {
96 return;
97 }
98
99 size_t idx = m_provider.ConsumeIntegralInRange<size_t>(0, m_entries.size() - 1);
100 Deallocate(m_entries[idx]);
101 if (idx != m_entries.size() - 1) {
102 m_entries[idx] = std::move(m_entries.back());
103 }
104 m_entries.pop_back();
105 }
106
107 void Clear()
108 {
109 while (!m_entries.empty()) {
110 Deallocate();
111 }
112
114 }
115
116 void Fuzz()
117 {
118 LIMITED_WHILE(m_provider.ConsumeBool(), 10000)
119 {
120 CallOneOf(
121 m_provider,
122 [&] { Allocate(); },
123 [&] { Deallocate(); });
124 }
125 Clear();
126 }
127};
128
129
130} // namespace
131
132FUZZ_TARGET(pool_resource)
133{
134 FuzzedDataProvider provider(buffer.data(), buffer.size());
135 CallOneOf(
136 provider,
137 [&] { PoolResourceFuzzer<128, 1>{provider}.Fuzz(); },
138 [&] { PoolResourceFuzzer<128, 2>{provider}.Fuzz(); },
139 [&] { PoolResourceFuzzer<128, 4>{provider}.Fuzz(); },
140 [&] { PoolResourceFuzzer<128, 8>{provider}.Fuzz(); },
141
142 [&] { PoolResourceFuzzer<8, 8>{provider}.Fuzz(); },
143 [&] { PoolResourceFuzzer<16, 16>{provider}.Fuzz(); },
144
145 [&] { PoolResourceFuzzer<256, alignof(max_align_t)>{provider}.Fuzz(); },
146 [&] { PoolResourceFuzzer<256, 64>{provider}.Fuzz(); });
147}
xoroshiro128++ PRNG.
Definition: random.h:416
A memory resource similar to std::pmr::unsynchronized_pool_resource, but optimized for node-based con...
Definition: pool.h:71
void Deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept
Returns a block to the freelists, or deletes the block when it did not come from the chunks.
Definition: pool.h:241
void * Allocate(std::size_t bytes, std::size_t alignment)
Allocates a block of bytes.
Definition: pool.h:212
static void CheckAllDataAccountedFor(const PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &resource)
Once all blocks are given back to the resource, tests that the freelists are consistent:
void fillrand(Span< std::byte > span) noexcept
Fill a Span with random bytes.
Definition: random.h:267
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:98
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition: fuzz.h:22
FUZZ_TARGET(pool_resource)
Span(T *, EndOrSize) -> Span< T >
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:35
#define expect(bit)
assert(!tx.IsCoinBase())