Bitcoin Core 28.99.0
P2P Digital Currency
bitset.cpp
Go to the documentation of this file.
1// Copyright (c) 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>
7#include <test/fuzz/util.h>
8#include <util/bitset.h>
9
10#include <bitset>
11#include <vector>
12
13namespace {
14
16uint8_t ReadByte(FuzzBufferType& buffer)
17{
18 if (buffer.empty()) return 0;
19 uint8_t ret = buffer.front();
20 buffer = buffer.subspan(1);
21 return ret;
22}
23
25template<typename S>
26void TestType(FuzzBufferType buffer)
27{
32 InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size());
33
34 using Sim = std::bitset<S::Size()>;
35 // Up to 4 real BitSets (initially 2).
36 std::vector<S> real(2);
37 // Up to 4 std::bitsets with the same corresponding contents.
38 std::vector<Sim> sim(2);
39
40 /* Compare sim[idx] with real[idx], using all inspector operations. */
41 auto compare_fn = [&](unsigned idx) {
42 /* iterators and operator[] */
43 auto it = real[idx].begin();
44 unsigned first = S::Size();
45 unsigned last = S::Size();
46 for (unsigned i = 0; i < S::Size(); ++i) {
47 bool match = (it != real[idx].end()) && *it == i;
48 assert(sim[idx][i] == real[idx][i]);
49 assert(match == real[idx][i]);
50 assert((it == real[idx].end()) != (it != real[idx].end()));
51 if (match) {
52 ++it;
53 if (first == S::Size()) first = i;
54 last = i;
55 }
56 }
57 assert(it == real[idx].end());
58 assert(!(it != real[idx].end()));
59 /* Any / None */
60 assert(sim[idx].any() == real[idx].Any());
61 assert(sim[idx].none() == real[idx].None());
62 /* First / Last */
63 if (sim[idx].any()) {
64 assert(first == real[idx].First());
65 assert(last == real[idx].Last());
66 }
67 /* Count */
68 assert(sim[idx].count() == real[idx].Count());
69 };
70
71 LIMITED_WHILE(buffer.size() > 0, 1000) {
72 // Read one byte to determine which operation to execute on the BitSets.
73 int command = ReadByte(buffer) % 64;
74 // Read another byte that determines which bitsets will be involved.
75 unsigned args = ReadByte(buffer);
76 unsigned dest = ((args & 7) * sim.size()) >> 3;
77 unsigned src = (((args >> 3) & 7) * sim.size()) >> 3;
78 unsigned aux = (((args >> 6) & 3) * sim.size()) >> 2;
79 // Args are in range for non-empty sim, or sim is completely empty and will be grown
80 assert((sim.empty() && dest == 0 && src == 0 && aux == 0) ||
81 (!sim.empty() && dest < sim.size() && src < sim.size() && aux < sim.size()));
82
83 // Pick one operation based on value of command. Not all operations are always applicable.
84 // Loop through the applicable ones until command reaches 0 (which avoids the need to
85 // compute the number of applicable commands ahead of time).
86 while (true) {
87 if (dest < sim.size() && command-- == 0) {
88 /* Set() (true) */
89 unsigned val = ReadByte(buffer) % S::Size();
90 assert(sim[dest][val] == real[dest][val]);
91 sim[dest].set(val);
92 real[dest].Set(val);
93 break;
94 } else if (dest < sim.size() && command-- == 0) {
95 /* Reset() */
96 unsigned val = ReadByte(buffer) % S::Size();
97 assert(sim[dest][val] == real[dest][val]);
98 sim[dest].reset(val);
99 real[dest].Reset(val);
100 break;
101 } else if (dest < sim.size() && command-- == 0) {
102 /* Set() (conditional) */
103 unsigned val = ReadByte(buffer) % S::Size();
104 assert(sim[dest][val] == real[dest][val]);
105 sim[dest].set(val, args >> 7);
106 real[dest].Set(val, args >> 7);
107 break;
108 } else if (sim.size() < 4 && command-- == 0) {
109 /* Construct empty. */
110 sim.resize(sim.size() + 1);
111 real.resize(real.size() + 1);
112 break;
113 } else if (sim.size() < 4 && command-- == 0) {
114 /* Construct singleton. */
115 unsigned val = ReadByte(buffer) % S::Size();
116 std::bitset<S::Size()> newset;
117 newset[val] = true;
118 sim.push_back(newset);
119 real.push_back(S::Singleton(val));
120 break;
121 } else if (dest < sim.size() && command-- == 0) {
122 /* Make random. */
123 compare_fn(dest);
124 sim[dest].reset();
125 real[dest] = S{};
126 for (unsigned i = 0; i < S::Size(); ++i) {
127 if (rng.randbool()) {
128 sim[dest][i] = true;
129 real[dest].Set(i);
130 }
131 }
132 break;
133 } else if (dest < sim.size() && command-- == 0) {
134 /* Assign initializer list. */
135 unsigned r1 = rng.randrange(S::Size());
136 unsigned r2 = rng.randrange(S::Size());
137 unsigned r3 = rng.randrange(S::Size());
138 compare_fn(dest);
139 sim[dest].reset();
140 real[dest] = {r1, r2, r3};
141 sim[dest].set(r1);
142 sim[dest].set(r2);
143 sim[dest].set(r3);
144 break;
145 } else if (!sim.empty() && command-- == 0) {
146 /* Destruct. */
147 compare_fn(sim.size() - 1);
148 sim.pop_back();
149 real.pop_back();
150 break;
151 } else if (sim.size() < 4 && src < sim.size() && command-- == 0) {
152 /* Copy construct. */
153 sim.emplace_back(sim[src]);
154 real.emplace_back(real[src]);
155 break;
156 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
157 /* Copy assign. */
158 compare_fn(dest);
159 sim[dest] = sim[src];
160 real[dest] = real[src];
161 break;
162 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
163 /* swap() function. */
164 swap(sim[dest], sim[src]);
165 swap(real[dest], real[src]);
166 break;
167 } else if (sim.size() < 4 && command-- == 0) {
168 /* Construct with initializer list. */
169 unsigned r1 = rng.randrange(S::Size());
170 unsigned r2 = rng.randrange(S::Size());
171 sim.emplace_back();
172 sim.back().set(r1);
173 sim.back().set(r2);
174 real.push_back(S{r1, r2});
175 break;
176 } else if (dest < sim.size() && command-- == 0) {
177 /* Fill() + copy assign. */
178 unsigned len = ReadByte(buffer) % S::Size();
179 compare_fn(dest);
180 sim[dest].reset();
181 for (unsigned i = 0; i < len; ++i) sim[dest][i] = true;
182 real[dest] = S::Fill(len);
183 break;
184 } else if (src < sim.size() && command-- == 0) {
185 /* Iterator copy based compare. */
186 unsigned val = ReadByte(buffer) % S::Size();
187 /* In a first loop, compare begin..end, and copy to it_copy at some point. */
188 auto it = real[src].begin(), it_copy = it;
189 for (unsigned i = 0; i < S::Size(); ++i) {
190 if (i == val) it_copy = it;
191 bool match = (it != real[src].end()) && *it == i;
192 assert(match == sim[src][i]);
193 if (match) ++it;
194 }
195 assert(it == real[src].end());
196 /* Then compare from the copied point again to end. */
197 for (unsigned i = val; i < S::Size(); ++i) {
198 bool match = (it_copy != real[src].end()) && *it_copy == i;
199 assert(match == sim[src][i]);
200 if (match) ++it_copy;
201 }
202 assert(it_copy == real[src].end());
203 break;
204 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
205 /* operator|= */
206 compare_fn(dest);
207 sim[dest] |= sim[src];
208 real[dest] |= real[src];
209 break;
210 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
211 /* operator&= */
212 compare_fn(dest);
213 sim[dest] &= sim[src];
214 real[dest] &= real[src];
215 break;
216 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
217 /* operator-= */
218 compare_fn(dest);
219 sim[dest] &= ~sim[src];
220 real[dest] -= real[src];
221 break;
222 } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
223 /* operator^= */
224 compare_fn(dest);
225 sim[dest] ^= sim[src];
226 real[dest] ^= real[src];
227 break;
228 } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
229 /* operator| */
230 compare_fn(dest);
231 sim[dest] = sim[src] | sim[aux];
232 real[dest] = real[src] | real[aux];
233 break;
234 } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
235 /* operator& */
236 compare_fn(dest);
237 sim[dest] = sim[src] & sim[aux];
238 real[dest] = real[src] & real[aux];
239 break;
240 } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
241 /* operator- */
242 compare_fn(dest);
243 sim[dest] = sim[src] & ~sim[aux];
244 real[dest] = real[src] - real[aux];
245 break;
246 } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
247 /* operator^ */
248 compare_fn(dest);
249 sim[dest] = sim[src] ^ sim[aux];
250 real[dest] = real[src] ^ real[aux];
251 break;
252 } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
253 /* IsSupersetOf() and IsSubsetOf() */
254 bool is_superset = (sim[aux] & ~sim[src]).none();
255 bool is_subset = (sim[src] & ~sim[aux]).none();
256 assert(real[src].IsSupersetOf(real[aux]) == is_superset);
257 assert(real[src].IsSubsetOf(real[aux]) == is_subset);
258 assert(real[aux].IsSupersetOf(real[src]) == is_subset);
259 assert(real[aux].IsSubsetOf(real[src]) == is_superset);
260 break;
261 } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
262 /* operator== and operator!= */
263 assert((sim[src] == sim[aux]) == (real[src] == real[aux]));
264 assert((sim[src] != sim[aux]) == (real[src] != real[aux]));
265 break;
266 } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
267 /* Overlaps() */
268 assert((sim[src] & sim[aux]).any() == real[src].Overlaps(real[aux]));
269 assert((sim[src] & sim[aux]).any() == real[aux].Overlaps(real[src]));
270 break;
271 }
272 }
273 }
274 /* Fully compare the final state. */
275 for (unsigned i = 0; i < sim.size(); ++i) {
276 compare_fn(i);
277 }
278}
279
280} // namespace
281
283{
284 unsigned typdat = ReadByte(buffer) % 8;
285 if (typdat == 0) {
286 /* 16 bits */
287 TestType<bitset_detail::IntBitSet<uint16_t>>(buffer);
288 TestType<bitset_detail::MultiIntBitSet<uint16_t, 1>>(buffer);
289 } else if (typdat == 1) {
290 /* 32 bits */
291 TestType<bitset_detail::MultiIntBitSet<uint16_t, 2>>(buffer);
292 TestType<bitset_detail::IntBitSet<uint32_t>>(buffer);
293 } else if (typdat == 2) {
294 /* 48 bits */
295 TestType<bitset_detail::MultiIntBitSet<uint16_t, 3>>(buffer);
296 } else if (typdat == 3) {
297 /* 64 bits */
298 TestType<bitset_detail::IntBitSet<uint64_t>>(buffer);
299 TestType<bitset_detail::MultiIntBitSet<uint64_t, 1>>(buffer);
300 TestType<bitset_detail::MultiIntBitSet<uint32_t, 2>>(buffer);
301 TestType<bitset_detail::MultiIntBitSet<uint16_t, 4>>(buffer);
302 } else if (typdat == 4) {
303 /* 96 bits */
304 TestType<bitset_detail::MultiIntBitSet<uint32_t, 3>>(buffer);
305 } else if (typdat == 5) {
306 /* 128 bits */
307 TestType<bitset_detail::MultiIntBitSet<uint64_t, 2>>(buffer);
308 TestType<bitset_detail::MultiIntBitSet<uint32_t, 4>>(buffer);
309 } else if (typdat == 6) {
310 /* 192 bits */
311 TestType<bitset_detail::MultiIntBitSet<uint64_t, 3>>(buffer);
312 } else if (typdat == 7) {
313 /* 256 bits */
314 TestType<bitset_detail::MultiIntBitSet<uint64_t, 4>>(buffer);
315 }
316}
int ret
const auto command
ArgsManager & args
Definition: bitcoind.cpp:277
FUZZ_TARGET(bitset)
Definition: bitset.cpp:282
xoroshiro128++ PRNG.
Definition: random.h:416
std::span< const uint8_t > FuzzBufferType
Definition: fuzz.h:25
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition: fuzz.h:22
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
static int count
assert(!tx.IsCoinBase())