Coverage Report

Created: 2025-04-14 16:24

/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
}