Branch data 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 : : #include <span.h>
6 : : #include <support/allocators/pool.h>
7 : : #include <test/fuzz/FuzzedDataProvider.h>
8 : : #include <test/fuzz/fuzz.h>
9 : : #include <test/fuzz/util.h>
10 : : #include <test/util/poolresourcetester.h>
11 : : #include <test/util/xoroshiro128plusplus.h>
12 : :
13 : : #include <cstdint>
14 : : #include <tuple>
15 : : #include <vector>
16 : :
17 : : namespace {
18 : :
19 : : template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
20 : : class PoolResourceFuzzer
21 : : {
22 : : FuzzedDataProvider& m_provider;
23 : : PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES> m_test_resource;
24 : 729 : uint64_t m_sequence{0};
25 [ + - ]: 902 : size_t m_total_allocated{};
26 : :
27 : : struct Entry {
28 : : Span<std::byte> span;
29 : : size_t alignment;
30 : : uint64_t seed;
31 : :
32 : 279613 : 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 : :
37 : : public:
38 : 1458 : PoolResourceFuzzer(FuzzedDataProvider& provider)
39 : 729 : : m_provider{provider},
40 : 729 : m_test_resource{provider.ConsumeIntegralInRange<size_t>(MAX_BLOCK_SIZE_BYTES, 262144)}
41 : : {
42 : 729 : }
43 : :
44 : 279613 : void Allocate(size_t size, size_t alignment)
45 : : {
46 [ + - + - : 279613 : assert(size > 0); // Must allocate at least 1 byte.
+ - + - +
- + - + -
+ - ]
47 [ + - + - : 279613 : assert(alignment > 0); // Alignment must be at least 1.
+ - + - +
- + - + -
+ - ]
48 [ + - + - : 279613 : assert((alignment & (alignment - 1)) == 0); // Alignment must be power of 2.
+ - + - +
- + - + -
+ - ]
49 [ + - + - : 279613 : assert((size & (alignment - 1)) == 0); // Size must be a multiple of alignment.
+ - + - +
- + - + -
+ - ]
50 : :
51 : 279613 : auto span = Span(static_cast<std::byte*>(m_test_resource.Allocate(size, alignment)), size);
52 : 279613 : m_total_allocated += size;
53 : :
54 : 279613 : auto ptr_val = reinterpret_cast<std::uintptr_t>(span.data());
55 [ + - + - : 279613 : assert((ptr_val & (alignment - 1)) == 0);
+ - + - +
- + - + -
+ - ]
56 : :
57 : 279613 : uint64_t seed = m_sequence++;
58 : 279613 : RandomContentFill(m_entries.emplace_back(span, alignment, seed));
59 : 279613 : }
60 : :
61 : : void
62 : 279940 : Allocate()
63 : : {
64 [ + + + + : 279940 : if (m_total_allocated > 0x1000000) return;
+ + + + +
+ + + + +
+ + ]
65 : 279613 : size_t alignment_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 7);
66 : 279613 : size_t alignment = 1 << alignment_bits;
67 : 279613 : size_t size_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 16 - alignment_bits);
68 : 279613 : size_t size = m_provider.ConsumeIntegralInRange<size_t>(1U << size_bits, (1U << (size_bits + 1)) - 1U) << alignment_bits;
69 : 279613 : Allocate(size, alignment);
70 : 279940 : }
71 : :
72 : 279613 : void RandomContentFill(Entry& entry)
73 : : {
74 : 279613 : XoRoShiRo128PlusPlus rng(entry.seed);
75 : 279613 : auto ptr = entry.span.data();
76 : 279613 : auto size = entry.span.size();
77 : :
78 [ + + + + : 186226488 : while (size >= 8) {
+ + + + +
+ + + + +
+ + ]
79 : 185946875 : auto r = rng();
80 : 185946875 : std::memcpy(ptr, &r, 8);
81 : 185946875 : size -= 8;
82 : 185946875 : ptr += 8;
83 : : }
84 [ + + + + : 279613 : if (size > 0) {
+ + + + +
+ + + + +
+ + ]
85 : 217389 : auto r = rng();
86 : 217389 : std::memcpy(ptr, &r, size);
87 : 217389 : }
88 : 279613 : }
89 : :
90 : 279613 : void RandomContentCheck(const Entry& entry)
91 : : {
92 : 279613 : XoRoShiRo128PlusPlus rng(entry.seed);
93 : 279613 : auto ptr = entry.span.data();
94 : 279613 : auto size = entry.span.size();
95 : :
96 : : std::byte buf[8];
97 [ + + + + : 186226488 : while (size >= 8) {
+ + + + +
+ + + + +
+ + ]
98 : 185946875 : auto r = rng();
99 : 185946875 : std::memcpy(buf, &r, 8);
100 [ + - + - : 185946875 : assert(std::memcmp(buf, ptr, 8) == 0);
+ - + - +
- + - + -
+ - ]
101 : 185946875 : size -= 8;
102 : 185946875 : ptr += 8;
103 : : }
104 [ + + + + : 279613 : if (size > 0) {
+ + + + +
+ + + + +
+ + ]
105 : 217389 : auto r = rng();
106 : 217389 : std::memcpy(buf, &r, size);
107 [ + - + - : 217389 : assert(std::memcmp(buf, ptr, size) == 0);
+ - + - +
- + - + -
+ - ]
108 : 217389 : }
109 : 279613 : }
110 : :
111 : 279613 : void Deallocate(const Entry& entry)
112 : : {
113 : 279613 : auto ptr_val = reinterpret_cast<std::uintptr_t>(entry.span.data());
114 [ + - + - : 279613 : assert((ptr_val & (entry.alignment - 1)) == 0);
+ - + - +
- + - + -
+ - ]
115 : 279613 : RandomContentCheck(entry);
116 : 279613 : m_total_allocated -= entry.span.size();
117 : 279613 : m_test_resource.Deallocate(entry.span.data(), entry.span.size(), entry.alignment);
118 : 279613 : }
119 : :
120 : 283943 : void Deallocate()
121 : : {
122 [ + + + + : 283943 : if (m_entries.empty()) {
+ + + + +
+ + + + +
+ + ]
123 : 4330 : return;
124 : : }
125 : :
126 : 279613 : size_t idx = m_provider.ConsumeIntegralInRange<size_t>(0, m_entries.size() - 1);
127 : 279613 : Deallocate(m_entries[idx]);
128 [ + + + + : 279613 : if (idx != m_entries.size() - 1) {
+ + + + +
+ + + + +
+ + ]
129 : 276569 : m_entries[idx] = std::move(m_entries.back());
130 : 276569 : }
131 : 279613 : m_entries.pop_back();
132 : 283943 : }
133 : :
134 : 729 : void Clear()
135 : : {
136 [ + + + + : 267662 : while (!m_entries.empty()) {
+ + + + +
+ + + + +
+ + ]
137 : 266933 : Deallocate();
138 : : }
139 : :
140 : 729 : PoolResourceTester::CheckAllDataAccountedFor(m_test_resource);
141 : 729 : }
142 : :
143 : 729 : void Fuzz()
144 : : {
145 [ + + + + : 297679 : LIMITED_WHILE(m_provider.ConsumeBool(), 10000)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + ]
146 : : {
147 : 296950 : CallOneOf(
148 : 296950 : m_provider,
149 : 576890 : [&] { Allocate(); },
150 : 313960 : [&] { Deallocate(); });
151 : 296950 : }
152 : 729 : Clear();
153 : 729 : }
154 : : };
155 : :
156 : :
157 : : } // namespace
158 : :
159 [ - + ]: 1075 : FUZZ_TARGET(pool_resource)
160 : : {
161 : 729 : FuzzedDataProvider provider(buffer.data(), buffer.size());
162 : 729 : CallOneOf(
163 : : provider,
164 [ + - ]: 821 : [&] { PoolResourceFuzzer<128, 1>{provider}.Fuzz(); },
165 [ + - ]: 827 : [&] { PoolResourceFuzzer<128, 2>{provider}.Fuzz(); },
166 [ + - ]: 819 : [&] { PoolResourceFuzzer<128, 4>{provider}.Fuzz(); },
167 [ + - ]: 815 : [&] { PoolResourceFuzzer<128, 8>{provider}.Fuzz(); },
168 : :
169 [ + - ]: 810 : [&] { PoolResourceFuzzer<8, 8>{provider}.Fuzz(); },
170 [ + - ]: 832 : [&] { PoolResourceFuzzer<16, 16>{provider}.Fuzz(); },
171 : :
172 [ + - ]: 814 : [&] { PoolResourceFuzzer<256, alignof(max_align_t)>{provider}.Fuzz(); },
173 [ + - ]: 823 : [&] { PoolResourceFuzzer<256, 64>{provider}.Fuzz(); });
174 : 729 : }
|