LCOV - code coverage report
Current view: top level - src/test/fuzz - bitset.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 195 195
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 31 31
Branches: 73.6 % 709 522

             Branch data     Line data    Source code
       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                 :     2019058 : uint8_t ReadByte(FuzzBufferType& buffer)
      17                 :             : {
      18         [ +  + ]:     2019058 :     if (buffer.empty()) return 0;
      19                 :     2017450 :     uint8_t ret = buffer.front();
      20                 :     2017450 :     buffer = buffer.subspan(1);
      21                 :     2017450 :     return ret;
      22                 :             : }
      23                 :             : 
      24                 :             : /** Perform a simulation fuzz test on BitSet type S. */
      25                 :             : template<typename S>
      26                 :        2373 : void TestType(FuzzBufferType buffer)
      27                 :             : {
      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                 :        2373 :     InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size());
      33                 :             : 
      34                 :             :     using Sim = std::bitset<S::Size()>;
      35                 :             :     // Up to 4 real BitSets (initially 2).
      36         [ +  - ]:        2373 :     std::vector<S> real(2);
      37                 :             :     // Up to 4 std::bitsets with the same corresponding contents.
      38         [ +  - ]:        2373 :     std::vector<Sim> sim(2);
      39                 :             : 
      40                 :             :     /* Compare sim[idx] with real[idx], using all inspector operations. */
      41                 :      809771 :     auto compare_fn = [&](unsigned idx) {
      42                 :             :         /* iterators and operator[] */
      43   [ +  +  +  +  :      403699 :         auto it = real[idx].begin();
                   +  + ]
      44                 :      403699 :         unsigned first = S::Size();
      45                 :      403699 :         unsigned last = S::Size();
      46   [ +  +  +  +  :    37351763 :         for (unsigned i = 0; i < S::Size(); ++i) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      47   [ +  +  +  +  :    36948064 :             bool match = (it != real[idx].end()) && *it == i;
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
      48   [ -  +  -  +  :    36948064 :             assert(sim[idx][i] == real[idx][i]);
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      49   [ -  +  -  +  :    36948064 :             assert(match == real[idx][i]);
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      50   [ -  +  -  +  :    36948064 :             assert((it == real[idx].end()) != (it != real[idx].end()));
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      51   [ +  +  +  +  :    36948064 :             if (match) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      52                 :     7825663 :                 ++it;
      53   [ +  +  +  +  :     7825663 :                 if (first == S::Size()) first = i;
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      54                 :             :                 last = i;
      55                 :             :             }
      56                 :             :         }
      57   [ -  +  -  +  :      403699 :         assert(it == real[idx].end());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      58   [ -  +  -  +  :      403699 :         assert(!(it != real[idx].end()));
                   -  + ]
      59                 :             :         /* Any / None */
      60   [ -  +  -  +  :      878802 :         assert(sim[idx].any() == real[idx].Any());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      61   [ -  +  -  +  :      727951 :         assert(sim[idx].none() == real[idx].None());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      62                 :             :         /* First / Last */
      63   [ +  +  +  +  :      403699 :         if (sim[idx].any()) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      64   [ -  +  -  +  :      306940 :             assert(first == real[idx].First());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      65   [ -  +  -  +  :      306940 :             assert(last == real[idx].Last());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      66                 :             :         }
      67                 :             :         /* Count */
      68   [ -  +  -  +  :      554550 :         assert(sim[idx].count() == real[idx].Count());
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  + ]
      69                 :             :     };
      70                 :             : 
      71   [ +  +  +  + ]:      863935 :     LIMITED_WHILE(buffer.size() > 0, 1000) {
      72                 :             :         // Read one byte to determine which operation to execute on the BitSets.
      73                 :      861562 :         int command = ReadByte(buffer) % 64;
      74                 :             :         // Read another byte that determines which bitsets will be involved.
      75                 :      861562 :         unsigned args = ReadByte(buffer);
      76         [ +  + ]:      861562 :         unsigned dest = ((args & 7) * sim.size()) >> 3;
      77                 :      861562 :         unsigned src = (((args >> 3) & 7) * sim.size()) >> 3;
      78                 :      861562 :         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   [ +  +  -  +  :      861562 :         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   [ +  +  +  + ]:     1937012 :             if (dest < sim.size() && command-- == 0) {
      88                 :             :                 /* Set() (true) */
      89                 :      107634 :                 unsigned val = ReadByte(buffer) % S::Size();
      90         [ -  + ]:      107634 :                 assert(sim[dest][val] == real[dest][val]);
      91         [ +  - ]:      107634 :                 sim[dest].set(val);
      92                 :      107634 :                 real[dest].Set(val);
      93                 :      107634 :                 break;
      94   [ +  +  +  + ]:     1829378 :             } else if (dest < sim.size() && command-- == 0) {
      95                 :             :                 /* Reset() */
      96                 :       34338 :                 unsigned val = ReadByte(buffer) % S::Size();
      97         [ -  + ]:       34338 :                 assert(sim[dest][val] == real[dest][val]);
      98         [ +  - ]:       34338 :                 sim[dest].reset(val);
      99                 :       34338 :                 real[dest].Reset(val);
     100                 :       34338 :                 break;
     101   [ +  +  +  + ]:     1795040 :             } else if (dest < sim.size() && command-- == 0) {
     102                 :             :                 /* Set() (conditional) */
     103                 :       28343 :                 unsigned val = ReadByte(buffer) % S::Size();
     104         [ -  + ]:       28343 :                 assert(sim[dest][val] == real[dest][val]);
     105         [ +  - ]:       28343 :                 sim[dest].set(val, args >> 7);
     106                 :       28343 :                 real[dest].Set(val, args >> 7);
     107                 :       28343 :                 break;
     108   [ +  +  +  + ]:     1766697 :             } else if (sim.size() < 4 && command-- == 0) {
     109                 :             :                 /* Construct empty. */
     110         [ +  - ]:       11682 :                 sim.resize(sim.size() + 1);
     111         [ +  - ]:       11682 :                 real.resize(real.size() + 1);
     112                 :             :                 break;
     113   [ +  +  +  + ]:     1755015 :             } else if (sim.size() < 4 && command-- == 0) {
     114                 :             :                 /* Construct singleton. */
     115                 :       12077 :                 unsigned val = ReadByte(buffer) % S::Size();
     116         [ +  + ]:       14962 :                 std::bitset<S::Size()> newset;
     117         [ +  - ]:       12077 :                 newset[val] = true;
     118         [ +  - ]:       12077 :                 sim.push_back(newset);
     119         [ +  - ]:       12077 :                 real.push_back(S::Singleton(val));
     120                 :             :                 break;
     121   [ +  +  +  + ]:     1742938 :             } else if (dest < sim.size() && command-- == 0) {
     122                 :             :                 /* Make random. */
     123                 :       44932 :                 compare_fn(dest);
     124                 :       44932 :                 sim[dest].reset();
     125                 :       44932 :                 real[dest] = S{};
     126         [ +  + ]:     4215988 :                 for (unsigned i = 0; i < S::Size(); ++i) {
     127         [ +  + ]:     4171056 :                     if (rng.randbool()) {
     128                 :     2084990 :                         sim[dest][i] = true;
     129                 :     2084990 :                         real[dest].Set(i);
     130                 :             :                     }
     131                 :             :                 }
     132                 :             :                 break;
     133   [ +  +  +  + ]:     1698006 :             } else if (dest < sim.size() && command-- == 0) {
     134                 :             :                 /* Assign initializer list. */
     135                 :       43421 :                 unsigned r1 = rng.randrange(S::Size());
     136                 :       43421 :                 unsigned r2 = rng.randrange(S::Size());
     137                 :       43421 :                 unsigned r3 = rng.randrange(S::Size());
     138                 :       43421 :                 compare_fn(dest);
     139                 :       43421 :                 sim[dest].reset();
     140                 :       43421 :                 real[dest] = {r1, r2, r3};
     141         [ +  - ]:       43421 :                 sim[dest].set(r1);
     142         [ +  - ]:       43421 :                 sim[dest].set(r2);
     143         [ +  - ]:       43421 :                 sim[dest].set(r3);
     144                 :             :                 break;
     145   [ +  +  +  + ]:     1654585 :             } else if (!sim.empty() && command-- == 0) {
     146                 :             :                 /* Destruct. */
     147                 :       49978 :                 compare_fn(sim.size() - 1);
     148                 :       49978 :                 sim.pop_back();
     149                 :       49978 :                 real.pop_back();
     150                 :             :                 break;
     151   [ +  +  +  +  :     1604607 :             } else if (sim.size() < 4 && src < sim.size() && command-- == 0) {
                   +  + ]
     152                 :             :                 /* Copy construct. */
     153         [ +  - ]:        8888 :                 sim.emplace_back(sim[src]);
     154         [ +  - ]:        8888 :                 real.emplace_back(real[src]);
     155                 :             :                 break;
     156   [ +  +  +  -  :     1595719 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     157                 :             :                 /* Copy assign. */
     158                 :       25436 :                 compare_fn(dest);
     159                 :       25436 :                 sim[dest] = sim[src];
     160                 :       25436 :                 real[dest] = real[src];
     161                 :       25436 :                 break;
     162   [ +  +  +  -  :     1570283 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     163                 :             :                 /* swap() function. */
     164                 :       32151 :                 swap(sim[dest], sim[src]);
     165                 :      727278 :                 swap(real[dest], real[src]);
     166                 :             :                 break;
     167   [ +  +  +  + ]:     1538132 :             } else if (sim.size() < 4 && command-- == 0) {
     168                 :             :                 /* Construct with initializer list. */
     169                 :       19622 :                 unsigned r1 = rng.randrange(S::Size());
     170                 :       19622 :                 unsigned r2 = rng.randrange(S::Size());
     171         [ +  - ]:       19622 :                 sim.emplace_back();
     172         [ +  - ]:       19622 :                 sim.back().set(r1);
     173         [ +  - ]:       19622 :                 sim.back().set(r2);
     174         [ +  - ]:      181611 :                 real.push_back(S{r1, r2});
     175                 :             :                 break;
     176   [ +  +  +  + ]:     1518510 :             } else if (dest < sim.size() && command-- == 0) {
     177                 :             :                 /* Fill() + copy assign. */
     178                 :       43941 :                 unsigned len = ReadByte(buffer) % S::Size();
     179                 :       43941 :                 compare_fn(dest);
     180                 :       43941 :                 sim[dest].reset();
     181         [ +  + ]:     1787405 :                 for (unsigned i = 0; i < len; ++i) sim[dest][i] = true;
     182                 :       43941 :                 real[dest] = S::Fill(len);
     183                 :       43941 :                 break;
     184   [ +  +  +  + ]:     1474569 :             } else if (src < sim.size() && command-- == 0) {
     185                 :             :                 /* Iterator copy based compare. */
     186                 :       68229 :                 unsigned val = ReadByte(buffer) % S::Size();
     187                 :             :                 /* In a first loop, compare begin..end, and copy to it_copy at some point. */
     188         [ +  + ]:       68229 :                 auto it = real[src].begin(), it_copy = it;
     189         [ +  + ]:     6228805 :                 for (unsigned i = 0; i < S::Size(); ++i) {
     190         [ +  + ]:     6160576 :                     if (i == val) it_copy = it;
     191   [ +  +  +  + ]:     6160576 :                     bool match = (it != real[src].end()) && *it == i;
     192         [ -  + ]:     6160576 :                     assert(match == sim[src][i]);
     193         [ +  + ]:     6160576 :                     if (match) ++it;
     194                 :             :                 }
     195         [ -  + ]:       68229 :                 assert(it == real[src].end());
     196                 :             :                 /* Then compare from the copied point again to end. */
     197         [ +  + ]:     2641032 :                 for (unsigned i = val; i < S::Size(); ++i) {
     198   [ +  +  +  + ]:     2572803 :                     bool match = (it_copy != real[src].end()) && *it_copy == i;
     199         [ -  + ]:     2572803 :                     assert(match == sim[src][i]);
     200         [ +  + ]:     2572803 :                     if (match) ++it_copy;
     201                 :             :                 }
     202         [ -  + ]:       68229 :                 assert(it_copy == real[src].end());
     203                 :             :                 break;
     204   [ +  +  +  -  :     1406340 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     205                 :             :                 /* operator|= */
     206                 :       25927 :                 compare_fn(dest);
     207                 :       25927 :                 sim[dest] |= sim[src];
     208                 :       25927 :                 real[dest] |= real[src];
     209                 :             :                 break;
     210   [ +  +  +  -  :     1380413 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     211                 :             :                 /* operator&= */
     212                 :       28097 :                 compare_fn(dest);
     213                 :       28097 :                 sim[dest] &= sim[src];
     214                 :       28097 :                 real[dest] &= real[src];
     215                 :             :                 break;
     216   [ +  +  +  -  :     1352316 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     217                 :             :                 /* operator-= */
     218                 :       22947 :                 compare_fn(dest);
     219                 :       22947 :                 sim[dest] &= ~sim[src];
     220                 :       22947 :                 real[dest] -= real[src];
     221                 :       18737 :                 break;
     222   [ +  +  +  -  :     1329369 :             } else if (src < sim.size() && dest < sim.size() && command-- == 0) {
                   +  + ]
     223                 :             :                 /* operator^= */
     224                 :       21482 :                 compare_fn(dest);
     225                 :       21482 :                 sim[dest] ^= sim[src];
     226                 :      716609 :                 real[dest] ^= real[src];
     227                 :             :                 break;
     228   [ +  +  +  -  :     1307887 :             } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
             +  -  +  + ]
     229                 :             :                 /* operator| */
     230                 :       22577 :                 compare_fn(dest);
     231                 :       26247 :                 sim[dest] = sim[src] | sim[aux];
     232                 :       26247 :                 real[dest] = real[src] | real[aux];
     233                 :       22577 :                 break;
     234   [ +  +  +  -  :     1285310 :             } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
             +  -  +  + ]
     235                 :             :                 /* operator& */
     236                 :       26249 :                 compare_fn(dest);
     237                 :       30968 :                 sim[dest] = sim[src] & sim[aux];
     238                 :       30968 :                 real[dest] = real[src] & real[aux];
     239                 :       26249 :                 break;
     240   [ +  +  +  -  :     1259061 :             } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
             +  -  +  + ]
     241                 :             :                 /* operator- */
     242                 :       21487 :                 compare_fn(dest);
     243                 :       24997 :                 sim[dest] = sim[src] & ~sim[aux];
     244                 :       21487 :                 real[dest] = real[src] - real[aux];
     245                 :       21487 :                 break;
     246   [ +  +  +  -  :     1237574 :             } else if (src < sim.size() && dest < sim.size() && aux < sim.size() && command-- == 0) {
             +  -  +  + ]
     247                 :             :                 /* operator^ */
     248                 :       20188 :                 compare_fn(dest);
     249                 :       23391 :                 sim[dest] = sim[src] ^ sim[aux];
     250                 :       23391 :                 real[dest] = real[src] ^ real[aux];
     251                 :       20188 :                 break;
     252   [ +  +  +  -  :     1217386 :             } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
                   +  + ]
     253                 :             :                 /* IsSupersetOf() and IsSubsetOf() */
     254         [ +  + ]:       99629 :                 bool is_superset = (sim[aux] & ~sim[src]).none();
     255         [ +  + ]:      100738 :                 bool is_subset = (sim[src] & ~sim[aux]).none();
     256         [ -  + ]:      126917 :                 assert(real[src].IsSupersetOf(real[aux]) == is_superset);
     257         [ -  + ]:       69224 :                 assert(real[src].IsSubsetOf(real[aux]) == is_subset);
     258         [ -  + ]:       57693 :                 assert(real[aux].IsSupersetOf(real[src]) == is_subset);
     259         [ -  + ]:       57693 :                 assert(real[aux].IsSubsetOf(real[src]) == is_superset);
     260                 :             :                 break;
     261   [ +  +  +  -  :     1148162 :             } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
                   +  + ]
     262                 :             :                 /* operator== and operator!= */
     263   [ +  +  -  + ]:       51026 :                 assert((sim[src] == sim[aux]) == (real[src] == real[aux]));
     264         [ -  + ]:       32227 :                 assert((sim[src] != sim[aux]) == (real[src] != real[aux]));
     265                 :             :                 break;
     266   [ +  +  +  -  :     1933804 :             } else if (src < sim.size() && aux < sim.size() && command-- == 0) {
             +  +  +  + ]
     267                 :             :                 /* Overlaps() */
     268   [ +  +  -  + ]:      115408 :                 assert((sim[src] & sim[aux]).any() == real[src].Overlaps(real[aux]));
     269   [ +  +  -  + ]:      115408 :                 assert((sim[src] & sim[aux]).any() == real[aux].Overlaps(real[src]));
     270                 :             :                 break;
     271                 :             :             }
     272                 :             :         }
     273                 :             :     }
     274                 :             :     /* Fully compare the final state. */
     275         [ +  + ]:        9410 :     for (unsigned i = 0; i < sim.size(); ++i) {
     276                 :        7037 :         compare_fn(i);
     277                 :             :     }
     278                 :        2373 : }
     279                 :             : 
     280                 :             : } // namespace
     281                 :             : 
     282         [ +  - ]:        1784 : FUZZ_TARGET(bitset)
     283                 :             : {
     284                 :        1372 :     unsigned typdat = ReadByte(buffer) % 8;
     285   [ +  +  +  +  :        1372 :     if (typdat == 0) {
             +  +  +  +  
                      - ]
     286                 :             :         /* 16 bits */
     287                 :         137 :         TestType<bitset_detail::IntBitSet<uint16_t>>(buffer);
     288                 :         137 :         TestType<bitset_detail::MultiIntBitSet<uint16_t, 1>>(buffer);
     289                 :             :     } else if (typdat == 1) {
     290                 :             :         /* 32 bits */
     291                 :         144 :         TestType<bitset_detail::MultiIntBitSet<uint16_t, 2>>(buffer);
     292                 :         144 :         TestType<bitset_detail::IntBitSet<uint32_t>>(buffer);
     293                 :             :     } else if (typdat == 2) {
     294                 :             :         /* 48 bits */
     295                 :         182 :         TestType<bitset_detail::MultiIntBitSet<uint16_t, 3>>(buffer);
     296                 :             :     } else if (typdat == 3) {
     297                 :             :         /* 64 bits */
     298                 :         181 :         TestType<bitset_detail::IntBitSet<uint64_t>>(buffer);
     299                 :         181 :         TestType<bitset_detail::MultiIntBitSet<uint64_t, 1>>(buffer);
     300                 :         181 :         TestType<bitset_detail::MultiIntBitSet<uint32_t, 2>>(buffer);
     301                 :         181 :         TestType<bitset_detail::MultiIntBitSet<uint16_t, 4>>(buffer);
     302                 :             :     } else if (typdat == 4) {
     303                 :             :         /* 96 bits */
     304                 :         167 :         TestType<bitset_detail::MultiIntBitSet<uint32_t, 3>>(buffer);
     305                 :             :     } else if (typdat == 5) {
     306                 :             :         /* 128 bits */
     307                 :         177 :         TestType<bitset_detail::MultiIntBitSet<uint64_t, 2>>(buffer);
     308                 :         177 :         TestType<bitset_detail::MultiIntBitSet<uint32_t, 4>>(buffer);
     309                 :             :     } else if (typdat == 6) {
     310                 :             :         /* 192 bits */
     311                 :         187 :         TestType<bitset_detail::MultiIntBitSet<uint64_t, 3>>(buffer);
     312                 :             :     } else if (typdat == 7) {
     313                 :             :         /* 256 bits */
     314                 :         197 :         TestType<bitset_detail::MultiIntBitSet<uint64_t, 4>>(buffer);
     315                 :             :     }
     316                 :        1372 : }
        

Generated by: LCOV version 2.0-1