LCOV - code coverage report
Current view: top level - src/test/fuzz - vecdeque.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 314 314
Test Date: 2024-09-01 05:20:30 Functions: 100.0 % 61 61
Branches: 69.3 % 2580 1788

             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/vecdeque.h>
       9                 :             : 
      10                 :             : #include <deque>
      11                 :             : #include <stdint.h>
      12                 :             : 
      13                 :             : namespace {
      14                 :             : 
      15                 :             : /** The maximum number of simultaneous buffers kept by the test. */
      16                 :             : static constexpr size_t MAX_BUFFERS{3};
      17                 :             : /** How many elements are kept in a buffer at most. */
      18                 :             : static constexpr size_t MAX_BUFFER_SIZE{48};
      19                 :             : /** How many operations are performed at most on the buffers in one test. */
      20                 :             : static constexpr size_t MAX_OPERATIONS{1024};
      21                 :             : 
      22                 :             : /** Perform a simulation fuzz test on VecDeque type T.
      23                 :             :  *
      24                 :             :  * T must be constructible from a uint64_t seed, comparable to other T, copyable, and movable.
      25                 :             :  */
      26                 :             : template<typename T, bool CheckNoneLeft>
      27                 :        4347 : void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak)
      28                 :             : {
      29                 :        4347 :     FuzzedDataProvider provider(buffer.data(), buffer.size());
      30                 :             :     // Local RNG, only used for the seeds to initialize T objects with.
      31                 :        4347 :     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak);
      32                 :             : 
      33                 :             :     // Real circular buffers.
      34                 :        4347 :     std::vector<VecDeque<T>> real;
      35   [ +  -  +  -  :        4347 :     real.reserve(MAX_BUFFERS);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      36                 :             :     // Simulated circular buffers.
      37                 :        4347 :     std::vector<std::deque<T>> sim;
      38   [ +  -  +  -  :        4347 :     sim.reserve(MAX_BUFFERS);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      39                 :             :     // Temporary object of type T.
      40                 :        4347 :     std::optional<T> tmp;
      41                 :             : 
      42                 :             :     // Compare a real and a simulated buffer.
      43                 :      980770 :     auto compare_fn = [](const VecDeque<T>& r, const std::deque<T>& s) {
      44   [ +  -  +  -  :      976423 :         assert(r.size() == s.size());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      45   [ +  -  +  -  :      976423 :         assert(r.empty() == s.empty());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      46   [ +  -  +  -  :      976423 :         assert(r.capacity() >= r.size());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      47   [ +  +  +  +  :      976423 :         if (s.size() == 0) return;
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      48   [ +  -  +  -  :      566069 :         assert(r.front() == s.front());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      49   [ +  -  +  -  :      566069 :         assert(r.back() == s.back());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      50   [ +  +  +  +  :    10983077 :         for (size_t i = 0; i < s.size(); ++i) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      51   [ +  -  +  -  :    10417008 :             assert(r[i] == s[i]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      52                 :    10417008 :         }
      53                 :      976423 :     };
      54                 :             : 
      55   [ -  +  +  +  :     2588523 :     LIMITED_WHILE(provider.remaining_bytes(), MAX_OPERATIONS) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
                      + ]
      56   [ -  +  -  +  :     2584176 :         int command = provider.ConsumeIntegral<uint8_t>() % 64;
          -  +  -  +  +  
             -  +  -  +  
                      - ]
      57   [ +  +  -  +  :     2584176 :         unsigned idx = real.empty() ? 0 : provider.ConsumeIntegralInRange<unsigned>(0, real.size() - 1);
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
      58                 :     2584176 :         const size_t num_buffers = sim.size();
      59                 :             :         // Pick one operation based on value of command. Not all operations are always applicable.
      60                 :             :         // Loop through the applicable ones until command reaches 0 (which avoids the need to
      61                 :             :         // compute the number of applicable commands ahead of time).
      62                 :     2584176 :         const bool non_empty{num_buffers != 0};
      63                 :     2584176 :         const bool non_full{num_buffers < MAX_BUFFERS};
      64   [ +  +  +  +  :     2584176 :         const bool partially_full{non_empty && non_full};
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      65                 :     2584176 :         const bool multiple_exist{num_buffers > 1};
      66   [ +  +  +  +  :     2584176 :         const bool existing_buffer_non_full{non_empty && sim[idx].size() < MAX_BUFFER_SIZE};
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      67   [ +  +  +  +  :     2584176 :         const bool existing_buffer_non_empty{non_empty && !sim[idx].empty()};
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      68   [ +  +  -  +  :     2584176 :         assert(non_full || non_empty);
          +  +  -  +  +  
          +  -  +  +  +  
          -  +  +  +  -  
          +  +  +  -  +  
             +  +  -  + ]
      69                 :     6013105 :         while (true) {
      70   [ +  +  +  +  :     6013105 :             if (non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      71                 :             :                 /* Default construct. */
      72   [ +  -  +  -  :       74879 :                 real.emplace_back();
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      73   [ +  -  +  -  :       74879 :                 sim.emplace_back();
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      74                 :       74879 :                 break;
      75                 :             :             }
      76   [ +  +  +  +  :     5938226 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      77                 :             :                 /* resize() */
      78   [ +  -  +  -  :      322644 :                 compare_fn(real[idx], sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      79         [ +  - ]:      322644 :                 size_t new_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);
      80   [ +  -  +  -  :      322644 :                 real[idx].resize(new_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      81   [ +  -  +  -  :      322644 :                 sim[idx].resize(new_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      82   [ +  -  +  -  :      322644 :                 assert(real[idx].size() == new_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      83                 :             :                 break;
      84                 :      322644 :             }
      85   [ +  +  +  +  :     5615582 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      86                 :             :                 /* clear() */
      87   [ +  -  +  -  :      138530 :                 compare_fn(real[idx], sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      88                 :      138530 :                 real[idx].clear();
      89                 :      138530 :                 sim[idx].clear();
      90   [ +  -  +  -  :      138530 :                 assert(real[idx].empty());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      91                 :      138530 :                 break;
      92                 :             :             }
      93   [ +  +  +  +  :     5477052 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
      94                 :             :                 /* Copy construct default. */
      95   [ +  -  +  -  :      127792 :                 compare_fn(real[idx], sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      96                 :      127792 :                 real[idx] = VecDeque<T>();
      97                 :      127792 :                 sim[idx].clear();
      98   [ +  -  +  -  :      127792 :                 assert(real[idx].size() == 0);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      99                 :      127792 :                 break;
     100                 :             :             }
     101   [ +  +  +  +  :     5349260 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     102                 :             :                 /* Destruct. */
     103   [ +  -  +  -  :      109802 :                 compare_fn(real.back(), sim.back());
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     104                 :      109802 :                 real.pop_back();
     105                 :      109802 :                 sim.pop_back();
     106                 :      109802 :                 break;
     107                 :             :             }
     108   [ +  +  +  +  :     5239458 :             if (partially_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     109                 :             :                 /* Copy construct. */
     110   [ +  -  +  -  :       21616 :                 real.emplace_back(real[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     111   [ +  -  +  -  :       21616 :                 sim.emplace_back(sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     112                 :       21616 :                 break;
     113                 :             :             }
     114   [ +  +  +  +  :     5217842 :             if (partially_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     115                 :             :                 /* Move construct. */
     116   [ +  -  +  -  :       23548 :                 VecDeque<T> copy(real[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     117   [ +  -  +  -  :       23548 :                 real.emplace_back(std::move(copy));
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     118   [ +  -  +  -  :       23548 :                 sim.emplace_back(sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     119                 :             :                 break;
     120                 :       23548 :             }
     121   [ +  +  +  +  :     5194294 :             if (multiple_exist && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     122                 :             :                 /* swap() */
     123                 :       57673 :                 swap(real[idx], real[(idx + 1) % num_buffers]);
     124                 :       57673 :                 swap(sim[idx], sim[(idx + 1) % num_buffers]);
     125                 :       57673 :                 break;
     126                 :             :             }
     127   [ +  +  +  +  :     5136621 :             if (multiple_exist && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     128                 :             :                 /* Copy assign. */
     129   [ +  -  +  -  :      135464 :                 compare_fn(real[idx], sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     130   [ +  -  +  -  :      135464 :                 real[idx] = real[(idx + 1) % num_buffers];
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     131   [ +  -  +  -  :      135464 :                 sim[idx] = sim[(idx + 1) % num_buffers];
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     132                 :      135464 :                 break;
     133                 :             :             }
     134   [ +  +  +  +  :     5001157 :             if (multiple_exist && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     135                 :             :                 /* Move assign. */
     136   [ +  -  +  -  :      131950 :                 VecDeque<T> copy(real[(idx + 1) % num_buffers]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     137   [ +  -  +  -  :      131950 :                 compare_fn(real[idx], sim[idx]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     138                 :      131950 :                 real[idx] = std::move(copy);
     139   [ +  -  +  -  :      131950 :                 sim[idx] = sim[(idx + 1) % num_buffers];
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     140                 :             :                 break;
     141                 :      131950 :             }
     142   [ +  +  +  +  :     4869207 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     143                 :             :                 /* Self swap() */
     144                 :       49784 :                 swap(real[idx], real[idx]);
     145                 :       49784 :                 break;
     146                 :             :             }
     147   [ +  +  +  +  :     4819423 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     148                 :             :                 /* Self-copy assign. */
     149   [ +  -  +  -  :       71582 :                 real[idx] = real[idx];
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     150                 :       71582 :                 break;
     151                 :             :             }
     152   [ +  +  +  +  :     4747841 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     153                 :             :                 /* Self-move assign. */
     154                 :             :                 // Do not use std::move(real[idx]) here: -Wself-move correctly warns about that.
     155                 :       87192 :                 real[idx] = static_cast<VecDeque<T>&&>(real[idx]);
     156                 :       87192 :                 break;
     157                 :             :             }
     158   [ +  +  +  +  :     4660649 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     159                 :             :                 /* reserve() */
     160         [ -  + ]:       60886 :                 size_t res_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);
     161                 :       60886 :                 size_t old_cap = real[idx].capacity();
     162                 :       60886 :                 size_t old_size = real[idx].size();
     163   [ +  -  -  +  :       60886 :                 real[idx].reserve(res_size);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     164   [ +  -  -  +  :       60886 :                 assert(real[idx].size() == old_size);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     165   [ +  -  -  +  :       60886 :                 assert(real[idx].capacity() == std::max(old_cap, res_size));
          -  +  -  +  -  
          +  -  +  -  +  
                   -  + ]
     166                 :             :                 break;
     167                 :       60886 :             }
     168   [ +  +  +  +  :     4599763 :             if (non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     169                 :             :                 /* shrink_to_fit() */
     170                 :       77483 :                 size_t old_size = real[idx].size();
     171   [ +  -  +  -  :       77483 :                 real[idx].shrink_to_fit();
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     172   [ +  -  +  -  :       77483 :                 assert(real[idx].size() == old_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     173   [ +  -  +  -  :       77483 :                 assert(real[idx].capacity() == old_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     174                 :             :                 break;
     175                 :       77483 :             }
     176   [ +  +  +  +  :     4522280 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     177                 :             :                 /* push_back() (copying) */
     178   [ -  +  -  +  :      126917 :                 tmp = T(rng.rand64());
          -  +  -  +  -  
                +  -  + ]
     179                 :      126917 :                 size_t old_size = real[idx].size();
     180                 :      126917 :                 size_t old_cap = real[idx].capacity();
     181   [ +  -  +  -  :      126917 :                 real[idx].push_back(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     182   [ +  -  +  -  :      126917 :                 sim[idx].push_back(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     183   [ -  +  -  +  :      126917 :                 assert(real[idx].size() == old_size + 1);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     184   [ +  +  +  +  :      126917 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     185   [ -  +  -  +  :       95956 :                     assert(real[idx].capacity() == old_cap);
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     186                 :       95956 :                 } else {
     187   [ -  +  -  +  :       30961 :                     assert(real[idx].capacity() > old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     188   [ +  -  +  -  :       30961 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     189                 :             :                 }
     190                 :             :                 break;
     191                 :      126917 :             }
     192   [ +  +  +  +  :     4395363 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     193                 :             :                 /* push_back() (moving) */
     194   [ +  -  +  -  :       71309 :                 tmp = T(rng.rand64());
          +  -  +  -  +  
                -  +  - ]
     195                 :       71309 :                 size_t old_size = real[idx].size();
     196                 :       71309 :                 size_t old_cap = real[idx].capacity();
     197   [ +  -  +  -  :       71309 :                 sim[idx].push_back(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     198   [ +  -  +  -  :       71309 :                 real[idx].push_back(std::move(*tmp));
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     199   [ +  -  +  -  :       71309 :                 assert(real[idx].size() == old_size + 1);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     200   [ +  +  +  +  :       71309 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     201   [ +  -  +  -  :       49882 :                     assert(real[idx].capacity() == old_cap);
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     202                 :       49882 :                 } else {
     203   [ -  +  -  +  :       21427 :                     assert(real[idx].capacity() > old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     204   [ -  +  -  +  :       21427 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     205                 :             :                 }
     206                 :             :                 break;
     207                 :       71309 :             }
     208   [ +  +  +  +  :     4324054 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     209                 :             :                 /* emplace_back() */
     210                 :      102032 :                 uint64_t seed{rng.rand64()};
     211                 :      102032 :                 size_t old_size = real[idx].size();
     212                 :      102032 :                 size_t old_cap = real[idx].capacity();
     213   [ +  -  +  -  :      102032 :                 sim[idx].emplace_back(seed);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     214   [ +  -  +  -  :      102032 :                 real[idx].emplace_back(seed);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     215   [ +  -  +  -  :      102032 :                 assert(real[idx].size() == old_size + 1);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     216   [ +  +  +  +  :      102032 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     217   [ -  +  +  -  :       72429 :                     assert(real[idx].capacity() == old_cap);
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     218                 :       72429 :                 } else {
     219   [ -  +  -  +  :       29603 :                     assert(real[idx].capacity() > old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     220   [ +  -  -  +  :       29603 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     221                 :             :                 }
     222                 :             :                 break;
     223                 :      102032 :             }
     224   [ +  +  +  +  :     4222022 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     225                 :             :                 /* push_front() (copying) */
     226   [ -  +  -  +  :       85092 :                 tmp = T(rng.rand64());
          -  +  -  +  -  
                +  -  + ]
     227                 :       85092 :                 size_t old_size = real[idx].size();
     228                 :       85092 :                 size_t old_cap = real[idx].capacity();
     229   [ +  -  +  -  :       85092 :                 real[idx].push_front(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     230   [ +  -  +  -  :       85092 :                 sim[idx].push_front(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     231   [ -  +  -  +  :       85092 :                 assert(real[idx].size() == old_size + 1);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     232   [ +  +  +  +  :       85092 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     233   [ +  -  -  +  :       55321 :                     assert(real[idx].capacity() == old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     234                 :       55321 :                 } else {
     235   [ -  +  -  +  :       29771 :                     assert(real[idx].capacity() > old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     236   [ +  -  -  +  :       29771 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     237                 :             :                 }
     238                 :             :                 break;
     239                 :       85092 :             }
     240   [ +  +  +  +  :     4136930 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     241                 :             :                 /* push_front() (moving) */
     242   [ +  -  +  -  :      104300 :                 tmp = T(rng.rand64());
          +  -  +  -  +  
                -  +  - ]
     243                 :      104300 :                 size_t old_size = real[idx].size();
     244                 :      104300 :                 size_t old_cap = real[idx].capacity();
     245   [ +  -  +  -  :      104300 :                 sim[idx].push_front(*tmp);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     246   [ +  -  +  -  :      104300 :                 real[idx].push_front(std::move(*tmp));
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     247   [ +  -  +  -  :      104300 :                 assert(real[idx].size() == old_size + 1);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     248   [ +  +  +  +  :      104300 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     249   [ +  -  +  -  :       78127 :                     assert(real[idx].capacity() == old_cap);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     250                 :       78127 :                 } else {
     251   [ +  -  +  -  :       26173 :                     assert(real[idx].capacity() > old_cap);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     252   [ +  -  +  -  :       26173 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     253                 :             :                 }
     254                 :             :                 break;
     255                 :      104300 :             }
     256   [ +  +  +  +  :     4032630 :             if (existing_buffer_non_full && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     257                 :             :                 /* emplace_front() */
     258                 :      171654 :                 uint64_t seed{rng.rand64()};
     259                 :      171654 :                 size_t old_size = real[idx].size();
     260                 :      171654 :                 size_t old_cap = real[idx].capacity();
     261   [ +  -  +  -  :      171654 :                 sim[idx].emplace_front(seed);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     262   [ +  -  +  -  :      171654 :                 real[idx].emplace_front(seed);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     263   [ +  -  +  -  :      171654 :                 assert(real[idx].size() == old_size + 1);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     264   [ +  +  +  +  :      171654 :                 if (old_cap > old_size) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     265   [ -  +  +  -  :      134687 :                     assert(real[idx].capacity() == old_cap);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     266                 :      134687 :                 } else {
     267   [ -  +  -  +  :       36967 :                     assert(real[idx].capacity() > old_cap);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     268   [ +  -  -  +  :       36967 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     269                 :             :                 }
     270                 :             :                 break;
     271                 :      171654 :             }
     272   [ +  +  +  +  :     3860976 :             if (existing_buffer_non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     273                 :             :                 /* front() [modifying] */
     274   [ -  +  -  +  :       49700 :                 tmp = T(rng.rand64());
          -  +  -  +  -  
                +  -  + ]
     275                 :       49700 :                 size_t old_size = real[idx].size();
     276   [ -  +  -  +  :       49700 :                 assert(sim[idx].front() == real[idx].front());
          -  +  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     277   [ +  -  +  -  :       49700 :                 sim[idx].front() = *tmp;
                   +  - ]
     278   [ +  -  +  -  :       49700 :                 real[idx].front() = std::move(*tmp);
                   +  - ]
     279   [ -  +  +  -  :       49700 :                 assert(real[idx].size() == old_size);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     280                 :             :                 break;
     281                 :       49700 :             }
     282   [ +  +  +  +  :     3811276 :             if (existing_buffer_non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     283                 :             :                 /* back() [modifying] */
     284   [ -  +  -  +  :       42259 :                 tmp = T(rng.rand64());
          -  +  -  +  -  
                +  -  + ]
     285                 :       42259 :                 size_t old_size = real[idx].size();
     286   [ -  +  -  +  :       42259 :                 assert(sim[idx].back() == real[idx].back());
          -  +  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     287   [ +  -  +  -  :       42259 :                 sim[idx].back() = *tmp;
                   +  - ]
     288   [ +  -  +  -  :       42259 :                 real[idx].back() = *tmp;
                   +  - ]
     289   [ -  +  -  +  :       42259 :                 assert(real[idx].size() == old_size);
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     290                 :             :                 break;
     291                 :       42259 :             }
     292   [ +  +  +  +  :     3769017 :             if (existing_buffer_non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     293                 :             :                 /* operator[] [modifying] */
     294   [ -  +  -  +  :       63315 :                 tmp = T(rng.rand64());
          -  +  -  +  -  
                +  -  + ]
     295         [ -  + ]:       63315 :                 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, sim[idx].size() - 1);
     296                 :       63315 :                 size_t old_size = real[idx].size();
     297   [ -  +  -  +  :       63315 :                 assert(sim[idx][pos] == real[idx][pos]);
          -  +  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     298   [ +  -  +  -  :       63315 :                 sim[idx][pos] = *tmp;
                   +  - ]
     299   [ +  -  +  -  :       63315 :                 real[idx][pos] = std::move(*tmp);
                   +  - ]
     300   [ -  +  -  +  :       63315 :                 assert(real[idx].size() == old_size);
          -  +  -  +  +  
             -  +  -  +  
                      - ]
     301                 :             :                 break;
     302                 :       63315 :             }
     303   [ +  +  +  +  :     3705702 :             if (existing_buffer_non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     304                 :             :                 /* pop_front() */
     305   [ -  +  -  +  :      224714 :                 assert(sim[idx].front() == real[idx].front());
          -  +  -  +  +  
          -  -  +  +  -  
          -  +  +  -  -  
                      + ]
     306                 :      224714 :                 size_t old_size = real[idx].size();
     307                 :      224714 :                 sim[idx].pop_front();
     308   [ -  +  -  +  :      224714 :                 real[idx].pop_front();
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     309   [ -  +  +  -  :      224714 :                 assert(real[idx].size() == old_size - 1);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     310                 :             :                 break;
     311                 :      224714 :             }
     312   [ +  +  +  +  :     3480988 :             if (existing_buffer_non_empty && command-- == 0) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
     313                 :             :                 /* pop_back() */
     314   [ -  +  -  +  :       52059 :                 assert(sim[idx].back() == real[idx].back());
          -  +  -  +  +  
          -  -  +  +  -  
          -  +  +  -  -  
                      + ]
     315                 :       52059 :                 size_t old_size = real[idx].size();
     316                 :       52059 :                 sim[idx].pop_back();
     317   [ -  +  -  +  :       52059 :                 real[idx].pop_back();
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     318   [ +  -  +  -  :       52059 :                 assert(real[idx].size() == old_size - 1);
          +  -  +  -  -  
             +  -  +  -  
                      + ]
     319                 :             :                 break;
     320                 :       52059 :             }
     321                 :             :         }
     322                 :     2584176 :     }
     323                 :             : 
     324                 :             :     /* Fully compare the final state. */
     325   [ +  +  +  +  :       14588 :     for (unsigned i = 0; i < sim.size(); ++i) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     326                 :             :         // Make sure const getters work.
     327                 :       10241 :         const VecDeque<T>& realbuf = real[i];
     328                 :       10241 :         const std::deque<T>& simbuf = sim[i];
     329   [ +  -  +  -  :       10241 :         compare_fn(realbuf, simbuf);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     330   [ +  +  +  +  :       37954 :         for (unsigned j = 0; j < sim.size(); ++j) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     331   [ +  -  +  -  :       27713 :             assert((realbuf == real[j]) == (simbuf == sim[j]));
          -  +  +  -  +  
          -  -  +  +  -  
          +  -  -  +  +  
          -  +  -  -  +  
          +  -  +  -  -  
          +  +  -  +  -  
          -  +  +  -  +  
                -  -  + ]
     332   [ +  -  +  -  :       27713 :             assert(((realbuf <=> real[j]) >= 0) == (simbuf >= sim[j]));
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     333   [ +  -  +  -  :       27713 :             assert(((realbuf <=> real[j]) <= 0) == (simbuf <= sim[j]));
          -  +  +  -  +  
          -  -  +  +  -  
          +  -  -  +  +  
          -  +  -  -  +  
          +  -  +  -  -  
          +  +  -  +  -  
          -  +  +  -  +  
                -  -  + ]
     334                 :       27713 :         }
     335                 :             :         // Clear out the buffers so we can check below that no objects exist anymore.
     336                 :       10241 :         sim[i].clear();
     337                 :       10241 :         real[i].clear();
     338                 :       10241 :     }
     339                 :             : 
     340                 :             :     if constexpr (CheckNoneLeft) {
     341                 :        1863 :         tmp = std::nullopt;
     342   [ +  -  +  -  :        1863 :         T::CheckNoneExist();
                   +  - ]
     343                 :             :     }
     344                 :        4347 : }
     345                 :             : 
     346                 :             : /** Data structure with built-in tracking of all existing objects. */
     347                 :             : template<size_t Size>
     348                 :             : class TrackedObj
     349                 :             : {
     350                 :             :     static_assert(Size > 0);
     351                 :             : 
     352                 :             :     /* Data type for map that actually stores the object data.
     353                 :             :      *
     354                 :             :      * The key is a pointer to the TrackedObj, the value is the uint64_t it was initialized with.
     355                 :             :      * Default-constructed and moved-from objects hold an std::nullopt.
     356                 :             :      */
     357                 :             :     using track_map_type = std::map<const TrackedObj<Size>*, std::optional<uint64_t>>;
     358                 :             : 
     359                 :             : private:
     360                 :             : 
     361                 :             :     /** Actual map. */
     362                 :           3 :     static inline track_map_type g_tracker;
     363                 :             : 
     364                 :             :     /** Iterators into the tracker map for this object.
     365                 :             :      *
     366                 :             :      * This is an array of size Size, all holding the same value, to give the object configurable
     367                 :             :      * size. The value is g_tracker.end() if this object is not fully initialized. */
     368                 :             :     typename track_map_type::iterator m_track_entry[Size];
     369                 :             : 
     370                 :    32905020 :     void Check() const
     371                 :             :     {
     372                 :    32905020 :         auto it = g_tracker.find(this);
     373   [ +  +  +  +  :   263240160 :         for (size_t i = 0; i < Size; ++i) {
                   +  + ]
     374   [ +  -  +  -  :   230335140 :             assert(m_track_entry[i] == it);
                   +  - ]
     375                 :   230335140 :         }
     376                 :    32905020 :     }
     377                 :             : 
     378                 :             :     /** Create entry for this object in g_tracker and populate m_track_entry. */
     379                 :     7637748 :     void Register()
     380                 :             :     {
     381                 :    61101984 :         auto [it, inserted] = g_tracker.emplace(this, std::nullopt);
     382   [ +  -  +  -  :     7637748 :         assert(inserted);
                   +  - ]
     383   [ +  +  +  +  :    61101984 :         for (size_t i = 0; i < Size; ++i) {
                   +  + ]
     384                 :    53464236 :             m_track_entry[i] = it;
     385                 :    53464236 :         }
     386                 :     7637748 :     }
     387                 :             : 
     388                 :     7637748 :     void Deregister()
     389                 :             :     {
     390                 :     7637748 :         Check();
     391   [ +  -  +  -  :     7637748 :         assert(m_track_entry[0] != g_tracker.end());
                   +  - ]
     392                 :     7637748 :         g_tracker.erase(m_track_entry[0]);
     393   [ +  +  +  +  :    61101984 :         for (size_t i = 0; i < Size; ++i) {
                   +  + ]
     394                 :    53464236 :             m_track_entry[i] = g_tracker.end();
     395                 :    53464236 :         }
     396                 :     7637748 :     }
     397                 :             : 
     398                 :             :     /** Get value corresponding to this object in g_tracker. */
     399                 :     9149112 :     std::optional<uint64_t>& Deref()
     400                 :             :     {
     401                 :     9149112 :         Check();
     402   [ +  -  +  -  :     9149112 :         assert(m_track_entry[0] != g_tracker.end());
                   +  - ]
     403                 :     9149112 :         return m_track_entry[0]->second;
     404                 :             :     }
     405                 :             : 
     406                 :             :     /** Get value corresponding to this object in g_tracker. */
     407                 :    16118160 :     const std::optional<uint64_t>& Deref() const
     408                 :             :     {
     409                 :    16118160 :         Check();
     410   [ +  -  +  -  :    16118160 :         assert(m_track_entry[0] != g_tracker.end());
                   +  - ]
     411                 :    16118160 :         return m_track_entry[0]->second;
     412                 :             :     }
     413                 :             : 
     414                 :             : public:
     415   [ +  -  +  -  :     7637748 :     ~TrackedObj() { Deregister(); }
                   +  - ]
     416                 :     2435100 :     TrackedObj() { Register(); }
     417                 :             : 
     418                 :      467256 :     TrackedObj(uint64_t value)
     419                 :             :     {
     420                 :      467256 :         Register();
     421                 :      467256 :         Deref() = value;
     422                 :      467256 :     }
     423                 :             : 
     424                 :     3707244 :     TrackedObj(const TrackedObj& other)
     425                 :             :     {
     426                 :     3707244 :         Register();
     427                 :     3707244 :         Deref() = other.Deref();
     428                 :     3707244 :     }
     429                 :             : 
     430                 :     1028148 :     TrackedObj(TrackedObj&& other)
     431                 :             :     {
     432                 :     1028148 :         Register();
     433                 :     1028148 :         Deref() = other.Deref();
     434                 :     1028148 :         other.Deref() = std::nullopt;
     435                 :     1028148 :     }
     436                 :             : 
     437                 :     1051890 :     TrackedObj& operator=(const TrackedObj& other)
     438                 :             :     {
     439   [ +  -  +  -  :     1051890 :         if (this == &other) return *this;
                   +  - ]
     440                 :     1051890 :         Deref() = other.Deref();
     441                 :     1051890 :         return *this;
     442                 :     1051890 :     }
     443                 :             : 
     444                 :      279426 :     TrackedObj& operator=(TrackedObj&& other)
     445                 :             :     {
     446   [ +  -  +  -  :      279426 :         if (this == &other) return *this;
                   +  - ]
     447                 :      279426 :         Deref() = other.Deref();
     448                 :      279426 :         other.Deref() = std::nullopt;
     449                 :      279426 :         return *this;
     450                 :      279426 :     }
     451                 :             : 
     452                 :     5256201 :     friend bool operator==(const TrackedObj& a, const TrackedObj& b)
     453                 :             :     {
     454                 :     5256201 :         return a.Deref() == b.Deref();
     455                 :             :     }
     456                 :             : 
     457                 :      254832 :     friend std::strong_ordering operator<=>(const TrackedObj& a, const TrackedObj& b)
     458                 :             :     {
     459                 :             :         // Libc++ 15 & 16 do not support std::optional<T>::operator<=> yet. See
     460                 :             :         // https://reviews.llvm.org/D146392.
     461   [ +  +  +  +  :      254832 :         if (!a.Deref().has_value() || !b.Deref().has_value()) {
          +  +  +  +  +  
                +  +  + ]
     462                 :      173376 :             return a.Deref().has_value() <=> b.Deref().has_value();
     463                 :             :         }
     464                 :       81456 :         return *a.Deref() <=> *b.Deref();
     465                 :      254832 :     }
     466                 :             : 
     467                 :        1863 :     static void CheckNoneExist()
     468                 :             :     {
     469   [ +  -  +  -  :        1863 :         assert(g_tracker.empty());
                   +  - ]
     470                 :        1863 :     }
     471                 :             : };
     472                 :             : 
     473                 :             : } // namespace
     474                 :             : 
     475   [ +  -  +  - ]:         624 : FUZZ_TARGET(vecdeque)
     476                 :             : {
     477                 :             :     // Run the test with simple uints (which satisfy all the trivial properties).
     478                 :             :     static_assert(std::is_trivially_copyable_v<uint32_t>);
     479                 :             :     static_assert(std::is_trivially_destructible_v<uint64_t>);
     480                 :         621 :     TestType<uint8_t, false>(buffer, 1);
     481                 :         621 :     TestType<uint16_t, false>(buffer, 2);
     482                 :         621 :     TestType<uint32_t, false>(buffer, 3);
     483                 :         621 :     TestType<uint64_t, false>(buffer, 4);
     484                 :             : 
     485                 :             :     // Run the test with TrackedObjs (which do not).
     486                 :             :     static_assert(!std::is_trivially_copyable_v<TrackedObj<3>>);
     487                 :             :     static_assert(!std::is_trivially_destructible_v<TrackedObj<17>>);
     488                 :         621 :     TestType<TrackedObj<1>, true>(buffer, 5);
     489                 :         621 :     TestType<TrackedObj<3>, true>(buffer, 6);
     490                 :         621 :     TestType<TrackedObj<17>, true>(buffer, 7);
     491                 :         621 : }
        

Generated by: LCOV version 2.0-1