/Users/mcomp/contrib/bitcoin/src/test/fuzz/bitset.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
13 | | namespace { |
14 | | |
15 | | /** Pop the first byte from a byte-span, and return it. */ |
16 | | uint8_t ReadByte(FuzzBufferType& buffer) |
17 | 0 | { |
18 | 0 | if (buffer.empty()) return 0; |
19 | 0 | uint8_t ret = buffer.front(); |
20 | 0 | buffer = buffer.subspan(1); |
21 | 0 | return ret; |
22 | 0 | } |
23 | | |
24 | | /** Perform a simulation fuzz test on BitSet type S. */ |
25 | | template<typename S> |
26 | | void TestType(FuzzBufferType buffer) |
27 | 0 | { |
28 | | /** This fuzz test's design is based on the assumption that the actual bits stored in the |
29 | | * bitsets and their simulations do not matter for the purpose of detecting edge cases, thus |
30 | | * these are taken from a deterministically-seeded RNG instead. To provide some level of |
31 | | * variation however, pick the seed based on the buffer size and size of the chosen bitset. */ |
32 | 0 | InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size()); |
33 | |
|
34 | 0 | using Sim = std::bitset<S::Size()>; |
35 | | // Up to 4 real BitSets (initially 2). |
36 | 0 | std::vector<S> real(2); |
37 | | // Up to 4 std::bitsets with the same corresponding contents. |
38 | 0 | std::vector<Sim> sim(2); |
39 | | |
40 | | /* Compare sim[idx] with real[idx], using all inspector operations. */ |
41 | 0 | auto compare_fn = [&](unsigned idx) { |
42 | | /* iterators and operator[] */ |
43 | 0 | auto it = real[idx].begin(); |
44 | 0 | unsigned first = S::Size(); |
45 | 0 | unsigned last = S::Size(); |
46 | 0 | for (unsigned i = 0; i < S::Size(); ++i) { |
47 | 0 | bool match = (it != real[idx].end()) && *it == i; |
48 | 0 | assert(sim[idx][i] == real[idx][i]); |
49 | 0 | assert(match == real[idx][i]); |
50 | 0 | assert((it == real[idx].end()) != (it != real[idx].end())); |
51 | 0 | if (match) { |
52 | 0 | ++it; |
53 | 0 | if (first == S::Size()) first = i; |
54 | 0 | last = i; |
55 | 0 | } |
56 | 0 | } |
57 | 0 | assert(it == real[idx].end()); |
58 | 0 | assert(!(it != real[idx].end())); |
59 | | /* Any / None */ |
60 | 0 | assert(sim[idx].any() == real[idx].Any()); |
61 | 0 | assert(sim[idx].none() == real[idx].None()); |
62 | | /* First / Last */ |
63 | 0 | if (sim[idx].any()) { |
64 | 0 | assert(first == real[idx].First()); |
65 | 0 | assert(last == real[idx].Last()); |
66 | 0 | } |
67 | | /* Count */ |
68 | 0 | assert(sim[idx].count() == real[idx].Count()); |
69 | 0 | }; Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetItEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj1EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetIjEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetIyEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj1EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj Unexecuted instantiation: bitset.cpp:_ZZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEEENKUljE_clEj |
70 | |
|
71 | 0 | LIMITED_WHILE(buffer.size() > 0, 1000) { |
72 | | // Read one byte to determine which operation to execute on the BitSets. |
73 | 0 | int command = ReadByte(buffer) % 64; |
74 | | // Read another byte that determines which bitsets will be involved. |
75 | 0 | unsigned args = ReadByte(buffer); |
76 | 0 | unsigned dest = ((args & 7) * sim.size()) >> 3; |
77 | 0 | unsigned src = (((args >> 3) & 7) * sim.size()) >> 3; |
78 | 0 | 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 | 0 | assert((sim.empty() && dest == 0 && src == 0 && aux == 0) || |
81 | 0 | (!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 | 0 | while (true) { |
87 | 0 | if (dest < sim.size() && command-- == 0) { |
88 | | /* Set() (true) */ |
89 | 0 | unsigned val = ReadByte(buffer) % S::Size(); |
90 | 0 | assert(sim[dest][val] == real[dest][val]); |
91 | 0 | sim[dest].set(val); |
92 | 0 | real[dest].Set(val); |
93 | 0 | break; |
94 | 0 | } else if (dest < sim.size() && command-- == 0) { |
95 | | /* Reset() */ |
96 | 0 | unsigned val = ReadByte(buffer) % S::Size(); |
97 | 0 | assert(sim[dest][val] == real[dest][val]); |
98 | 0 | sim[dest].reset(val); |
99 | 0 | real[dest].Reset(val); |
100 | 0 | break; |
101 | 0 | } else if (dest < sim.size() && command-- == 0) { |
102 | | /* Set() (conditional) */ |
103 | 0 | unsigned val = ReadByte(buffer) % S::Size(); |
104 | 0 | assert(sim[dest][val] == real[dest][val]); |
105 | 0 | sim[dest].set(val, args >> 7); |
106 | 0 | real[dest].Set(val, args >> 7); |
107 | 0 | break; |
108 | 0 | } else if (sim.size() < 4 && command-- == 0) { |
109 | | /* Construct empty. */ |
110 | 0 | sim.resize(sim.size() + 1); |
111 | 0 | real.resize(real.size() + 1); |
112 | 0 | break; |
113 | 0 | } else if (sim.size() < 4 && command-- == 0) { |
114 | | /* Construct singleton. */ |
115 | 0 | unsigned val = ReadByte(buffer) % S::Size(); |
116 | 0 | std::bitset<S::Size()> newset; |
117 | 0 | newset[val] = true; |
118 | 0 | sim.push_back(newset); |
119 | 0 | real.push_back(S::Singleton(val)); |
120 | 0 | break; |
121 | 0 | } else if (dest < sim.size() && command-- == 0) { |
122 | | /* Make random. */ |
123 | 0 | compare_fn(dest); |
124 | 0 | sim[dest].reset(); |
125 | 0 | real[dest] = S{}; |
126 | 0 | for (unsigned i = 0; i < S::Size(); ++i) { |
127 | 0 | if (rng.randbool()) { |
128 | 0 | sim[dest][i] = true; |
129 | 0 | real[dest].Set(i); |
130 | 0 | } |
131 | 0 | } |
132 | 0 | break; |
133 | 0 | } else if (dest < sim.size() && command-- == 0) { |
134 | | /* Assign initializer list. */ |
135 | 0 | unsigned r1 = rng.randrange(S::Size()); |
136 | 0 | unsigned r2 = rng.randrange(S::Size()); |
137 | 0 | unsigned r3 = rng.randrange(S::Size()); |
138 | 0 | compare_fn(dest); |
139 | 0 | sim[dest].reset(); |
140 | 0 | real[dest] = {r1, r2, r3}; |
141 | 0 | sim[dest].set(r1); |
142 | 0 | sim[dest].set(r2); |
143 | 0 | sim[dest].set(r3); |
144 | 0 | break; |
145 | 0 | } else if (!sim.empty() && command-- == 0) { |
146 | | /* Destruct. */ |
147 | 0 | compare_fn(sim.size() - 1); |
148 | 0 | sim.pop_back(); |
149 | 0 | real.pop_back(); |
150 | 0 | break; |
151 | 0 | } else if (sim.size() < 4 && src < sim.size() && command-- == 0) { |
152 | | /* Copy construct. */ |
153 | 0 | sim.emplace_back(sim[src]); |
154 | 0 | real.emplace_back(real[src]); |
155 | 0 | break; |
156 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
157 | | /* Copy assign. */ |
158 | 0 | compare_fn(dest); |
159 | 0 | sim[dest] = sim[src]; |
160 | 0 | real[dest] = real[src]; |
161 | 0 | break; |
162 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
163 | | /* swap() function. */ |
164 | 0 | swap(sim[dest], sim[src]); |
165 | 0 | swap(real[dest], real[src]); |
166 | 0 | break; |
167 | 0 | } else if (sim.size() < 4 && command-- == 0) { |
168 | | /* Construct with initializer list. */ |
169 | 0 | unsigned r1 = rng.randrange(S::Size()); |
170 | 0 | unsigned r2 = rng.randrange(S::Size()); |
171 | 0 | sim.emplace_back(); |
172 | 0 | sim.back().set(r1); |
173 | 0 | sim.back().set(r2); |
174 | 0 | real.push_back(S{r1, r2}); |
175 | 0 | break; |
176 | 0 | } else if (dest < sim.size() && command-- == 0) { |
177 | | /* Fill() + copy assign. */ |
178 | 0 | unsigned len = ReadByte(buffer) % S::Size(); |
179 | 0 | compare_fn(dest); |
180 | 0 | sim[dest].reset(); |
181 | 0 | for (unsigned i = 0; i < len; ++i) sim[dest][i] = true; |
182 | 0 | real[dest] = S::Fill(len); |
183 | 0 | break; |
184 | 0 | } else if (src < sim.size() && command-- == 0) { |
185 | | /* Iterator copy based compare. */ |
186 | 0 | unsigned val = ReadByte(buffer) % S::Size(); |
187 | | /* In a first loop, compare begin..end, and copy to it_copy at some point. */ |
188 | 0 | auto it = real[src].begin(), it_copy = it; |
189 | 0 | for (unsigned i = 0; i < S::Size(); ++i) { |
190 | 0 | if (i == val) it_copy = it; |
191 | 0 | bool match = (it != real[src].end()) && *it == i; |
192 | 0 | assert(match == sim[src][i]); |
193 | 0 | if (match) ++it; |
194 | 0 | } |
195 | 0 | assert(it == real[src].end()); |
196 | | /* Then compare from the copied point again to end. */ |
197 | 0 | for (unsigned i = val; i < S::Size(); ++i) { |
198 | 0 | bool match = (it_copy != real[src].end()) && *it_copy == i; |
199 | 0 | assert(match == sim[src][i]); |
200 | 0 | if (match) ++it_copy; |
201 | 0 | } |
202 | 0 | assert(it_copy == real[src].end()); |
203 | 0 | break; |
204 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
205 | | /* operator|= */ |
206 | 0 | compare_fn(dest); |
207 | 0 | sim[dest] |= sim[src]; |
208 | 0 | real[dest] |= real[src]; |
209 | 0 | break; |
210 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
211 | | /* operator&= */ |
212 | 0 | compare_fn(dest); |
213 | 0 | sim[dest] &= sim[src]; |
214 | 0 | real[dest] &= real[src]; |
215 | 0 | break; |
216 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
217 | | /* operator-= */ |
218 | 0 | compare_fn(dest); |
219 | 0 | sim[dest] &= ~sim[src]; |
220 | 0 | real[dest] -= real[src]; |
221 | 0 | break; |
222 | 0 | } else if (src < sim.size() && dest < sim.size() && command-- == 0) { |
223 | | /* operator^= */ |
224 | 0 | compare_fn(dest); |
225 | 0 | sim[dest] ^= sim[src]; |
226 | 0 | real[dest] ^= real[src]; |
227 | 0 | break; |
228 | 0 | } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { |
229 | | /* operator| */ |
230 | 0 | compare_fn(dest); |
231 | 0 | sim[dest] = sim[src] | sim[aux]; |
232 | 0 | real[dest] = real[src] | real[aux]; |
233 | 0 | break; |
234 | 0 | } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { |
235 | | /* operator& */ |
236 | 0 | compare_fn(dest); |
237 | 0 | sim[dest] = sim[src] & sim[aux]; |
238 | 0 | real[dest] = real[src] & real[aux]; |
239 | 0 | break; |
240 | 0 | } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { |
241 | | /* operator- */ |
242 | 0 | compare_fn(dest); |
243 | 0 | sim[dest] = sim[src] & ~sim[aux]; |
244 | 0 | real[dest] = real[src] - real[aux]; |
245 | 0 | break; |
246 | 0 | } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) { |
247 | | /* operator^ */ |
248 | 0 | compare_fn(dest); |
249 | 0 | sim[dest] = sim[src] ^ sim[aux]; |
250 | 0 | real[dest] = real[src] ^ real[aux]; |
251 | 0 | break; |
252 | 0 | } else if (src < sim.size() && aux < sim.size() && command-- == 0) { |
253 | | /* IsSupersetOf() and IsSubsetOf() */ |
254 | 0 | bool is_superset = (sim[aux] & ~sim[src]).none(); |
255 | 0 | bool is_subset = (sim[src] & ~sim[aux]).none(); |
256 | 0 | assert(real[src].IsSupersetOf(real[aux]) == is_superset); |
257 | 0 | assert(real[src].IsSubsetOf(real[aux]) == is_subset); |
258 | 0 | assert(real[aux].IsSupersetOf(real[src]) == is_subset); |
259 | 0 | assert(real[aux].IsSubsetOf(real[src]) == is_superset); |
260 | 0 | break; |
261 | 0 | } else if (src < sim.size() && aux < sim.size() && command-- == 0) { |
262 | | /* operator== and operator!= */ |
263 | 0 | assert((sim[src] == sim[aux]) == (real[src] == real[aux])); |
264 | 0 | assert((sim[src] != sim[aux]) == (real[src] != real[aux])); |
265 | 0 | break; |
266 | 0 | } else if (src < sim.size() && aux < sim.size() && command-- == 0) { |
267 | | /* Overlaps() */ |
268 | 0 | assert((sim[src] & sim[aux]).any() == real[src].Overlaps(real[aux])); |
269 | 0 | assert((sim[src] & sim[aux]).any() == real[aux].Overlaps(real[src])); |
270 | 0 | break; |
271 | 0 | } |
272 | 0 | } |
273 | 0 | } |
274 | | /* Fully compare the final state. */ |
275 | 0 | for (unsigned i = 0; i < sim.size(); ++i) { |
276 | 0 | compare_fn(i); |
277 | 0 | } |
278 | 0 | } Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetItEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj1EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetIjEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail9IntBitSetIyEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj1EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetItLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj2EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIjLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj3EEEEEvNSt3__14spanIKhLm18446744073709551615EEE Unexecuted instantiation: bitset.cpp:_ZN12_GLOBAL__N_18TestTypeIN13bitset_detail14MultiIntBitSetIyLj4EEEEEvNSt3__14spanIKhLm18446744073709551615EEE |
279 | | |
280 | | } // namespace |
281 | | |
282 | | FUZZ_TARGET(bitset) |
283 | 0 | { |
284 | 0 | unsigned typdat = ReadByte(buffer) % 8; |
285 | 0 | if (typdat == 0) { |
286 | | /* 16 bits */ |
287 | 0 | TestType<bitset_detail::IntBitSet<uint16_t>>(buffer); |
288 | 0 | TestType<bitset_detail::MultiIntBitSet<uint16_t, 1>>(buffer); |
289 | 0 | } else if (typdat == 1) { |
290 | | /* 32 bits */ |
291 | 0 | TestType<bitset_detail::MultiIntBitSet<uint16_t, 2>>(buffer); |
292 | 0 | TestType<bitset_detail::IntBitSet<uint32_t>>(buffer); |
293 | 0 | } else if (typdat == 2) { |
294 | | /* 48 bits */ |
295 | 0 | TestType<bitset_detail::MultiIntBitSet<uint16_t, 3>>(buffer); |
296 | 0 | } else if (typdat == 3) { |
297 | | /* 64 bits */ |
298 | 0 | TestType<bitset_detail::IntBitSet<uint64_t>>(buffer); |
299 | 0 | TestType<bitset_detail::MultiIntBitSet<uint64_t, 1>>(buffer); |
300 | 0 | TestType<bitset_detail::MultiIntBitSet<uint32_t, 2>>(buffer); |
301 | 0 | TestType<bitset_detail::MultiIntBitSet<uint16_t, 4>>(buffer); |
302 | 0 | } else if (typdat == 4) { |
303 | | /* 96 bits */ |
304 | 0 | TestType<bitset_detail::MultiIntBitSet<uint32_t, 3>>(buffer); |
305 | 0 | } else if (typdat == 5) { |
306 | | /* 128 bits */ |
307 | 0 | TestType<bitset_detail::MultiIntBitSet<uint64_t, 2>>(buffer); |
308 | 0 | TestType<bitset_detail::MultiIntBitSet<uint32_t, 4>>(buffer); |
309 | 0 | } else if (typdat == 6) { |
310 | | /* 192 bits */ |
311 | 0 | TestType<bitset_detail::MultiIntBitSet<uint64_t, 3>>(buffer); |
312 | 0 | } else if (typdat == 7) { |
313 | | /* 256 bits */ |
314 | 0 | TestType<bitset_detail::MultiIntBitSet<uint64_t, 4>>(buffer); |
315 | 0 | } |
316 | 0 | } |