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 % 276 276
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 58 58
Branches: 69.0 % 562 388

             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                 :        2590 : void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak)
      28                 :             : {
      29                 :        2590 :     FuzzedDataProvider provider(buffer.data(), buffer.size());
      30                 :             :     // Local RNG, only used for the seeds to initialize T objects with.
      31                 :        2590 :     InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak);
      32                 :             : 
      33                 :             :     // Real circular buffers.
      34                 :        2590 :     std::vector<VecDeque<T>> real;
      35         [ +  - ]:        2590 :     real.reserve(MAX_BUFFERS);
      36                 :             :     // Simulated circular buffers.
      37                 :        2590 :     std::vector<std::deque<T>> sim;
      38         [ +  - ]:        2590 :     sim.reserve(MAX_BUFFERS);
      39                 :             :     // Temporary object of type T.
      40                 :        2590 :     std::optional<T> tmp;
      41                 :             : 
      42                 :             :     // Compare a real and a simulated buffer.
      43         [ -  + ]:      471450 :     auto compare_fn = [](const VecDeque<T>& r, const std::deque<T>& s) {
      44   [ -  +  -  +  :      471450 :         assert(r.size() == s.size());
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      45   [ -  +  -  +  :      471450 :         assert(r.empty() == s.empty());
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      46   [ -  +  -  +  :      471450 :         assert(r.capacity() >= r.size());
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      47   [ +  +  +  +  :      471450 :         if (s.size() == 0) return;
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      48   [ -  +  -  +  :      278824 :         assert(r.front() == s.front());
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      49   [ -  +  -  +  :      278824 :         assert(r.back() == s.back());
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      50   [ +  +  +  +  :     6501992 :         for (size_t i = 0; i < s.size(); ++i) {
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      51   [ -  +  -  +  :     6223168 :             assert(r[i] == s[i]);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      52                 :             :         }
      53                 :             :     };
      54                 :             : 
      55   [ +  +  +  + ]:     1291171 :     LIMITED_WHILE(provider.remaining_bytes(), MAX_OPERATIONS) {
      56                 :     1288581 :         int command = provider.ConsumeIntegral<uint8_t>() % 64;
      57   [ +  +  +  + ]:     1288581 :         unsigned idx = real.empty() ? 0 : provider.ConsumeIntegralInRange<unsigned>(0, real.size() - 1);
      58                 :     1288581 :         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                 :     1288581 :         const bool non_empty{num_buffers != 0};
      63                 :     1288581 :         const bool non_full{num_buffers < MAX_BUFFERS};
      64                 :     1288581 :         const bool partially_full{non_empty && non_full};
      65                 :     1288581 :         const bool multiple_exist{num_buffers > 1};
      66   [ +  +  +  + ]:     1288581 :         const bool existing_buffer_non_full{non_empty && sim[idx].size() < MAX_BUFFER_SIZE};
      67   [ +  -  +  + ]:     1640639 :         const bool existing_buffer_non_empty{non_empty && !sim[idx].empty()};
      68                 :             :         assert(non_full || non_empty);
      69                 :             :         while (true) {
      70   [ +  +  +  + ]:     3076402 :             if (non_full && command-- == 0) {
      71                 :             :                 /* Default construct. */
      72         [ +  - ]:       38640 :                 real.emplace_back();
      73         [ +  - ]:       38640 :                 sim.emplace_back();
      74                 :             :                 break;
      75                 :             :             }
      76   [ +  +  +  + ]:     3037762 :             if (non_empty && command-- == 0) {
      77                 :             :                 /* resize() */
      78                 :      135681 :                 compare_fn(real[idx], sim[idx]);
      79                 :      135681 :                 size_t new_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);
      80         [ +  - ]:      135681 :                 real[idx].resize(new_size);
      81         [ +  - ]:      135681 :                 sim[idx].resize(new_size);
      82         [ -  + ]:      135681 :                 assert(real[idx].size() == new_size);
      83                 :             :                 break;
      84                 :             :             }
      85   [ +  +  +  + ]:     2902081 :             if (non_empty && command-- == 0) {
      86                 :             :                 /* clear() */
      87                 :       69622 :                 compare_fn(real[idx], sim[idx]);
      88                 :       69622 :                 real[idx].clear();
      89                 :       69622 :                 sim[idx].clear();
      90         [ -  + ]:       69622 :                 assert(real[idx].empty());
      91                 :             :                 break;
      92                 :             :             }
      93   [ +  +  +  + ]:     2832459 :             if (non_empty && command-- == 0) {
      94                 :             :                 /* Copy construct default. */
      95                 :       73465 :                 compare_fn(real[idx], sim[idx]);
      96                 :       73465 :                 real[idx] = VecDeque<T>();
      97                 :       73465 :                 sim[idx].clear();
      98         [ -  + ]:       73465 :                 assert(real[idx].size() == 0);
      99                 :             :                 break;
     100                 :             :             }
     101   [ +  +  +  + ]:     2758994 :             if (non_empty && command-- == 0) {
     102                 :             :                 /* Destruct. */
     103                 :       54180 :                 compare_fn(real.back(), sim.back());
     104                 :       54180 :                 real.pop_back();
     105                 :       54180 :                 sim.pop_back();
     106                 :             :                 break;
     107                 :             :             }
     108   [ +  +  +  + ]:     2704814 :             if (partially_full && command-- == 0) {
     109                 :             :                 /* Copy construct. */
     110         [ +  - ]:        6265 :                 real.emplace_back(real[idx]);
     111         [ +  - ]:        6265 :                 sim.emplace_back(sim[idx]);
     112                 :             :                 break;
     113                 :             :             }
     114   [ +  +  +  + ]:     2698549 :             if (partially_full && command-- == 0) {
     115                 :             :                 /* Move construct. */
     116         [ +  - ]:       15323 :                 VecDeque<T> copy(real[idx]);
     117         [ +  - ]:       15323 :                 real.emplace_back(std::move(copy));
     118         [ +  - ]:       15323 :                 sim.emplace_back(sim[idx]);
     119                 :             :                 break;
     120                 :       15323 :             }
     121   [ +  +  +  + ]:     2683226 :             if (multiple_exist && command-- == 0) {
     122                 :             :                 /* swap() */
     123                 :       18466 :                 swap(real[idx], real[(idx + 1) % num_buffers]);
     124                 :       18466 :                 swap(sim[idx], sim[(idx + 1) % num_buffers]);
     125                 :             :                 break;
     126                 :             :             }
     127   [ +  +  +  + ]:     2664760 :             if (multiple_exist && command-- == 0) {
     128                 :             :                 /* Copy assign. */
     129                 :       67277 :                 compare_fn(real[idx], sim[idx]);
     130         [ +  - ]:       67277 :                 real[idx] = real[(idx + 1) % num_buffers];
     131         [ +  - ]:       67277 :                 sim[idx] = sim[(idx + 1) % num_buffers];
     132                 :             :                 break;
     133                 :             :             }
     134   [ +  +  +  + ]:     2597483 :             if (multiple_exist && command-- == 0) {
     135                 :             :                 /* Move assign. */
     136         [ +  - ]:       65177 :                 VecDeque<T> copy(real[(idx + 1) % num_buffers]);
     137                 :       65177 :                 compare_fn(real[idx], sim[idx]);
     138         [ +  - ]:       65177 :                 real[idx] = std::move(copy);
     139         [ +  - ]:       65177 :                 sim[idx] = sim[(idx + 1) % num_buffers];
     140                 :             :                 break;
     141                 :       65177 :             }
     142   [ +  +  +  + ]:     2532306 :             if (non_empty && command-- == 0) {
     143                 :             :                 /* Self swap() */
     144                 :     1288581 :                 swap(real[idx], real[idx]);
     145                 :             :                 break;
     146                 :             :             }
     147   [ +  +  +  + ]:     2511915 :             if (non_empty && command-- == 0) {
     148                 :             :                 /* Self-copy assign. */
     149         [ +  - ]:       30254 :                 real[idx] = real[idx];
     150                 :             :                 break;
     151                 :             :             }
     152   [ +  +  +  + ]:     2481661 :             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                 :     1288581 :                 real[idx] = static_cast<VecDeque<T>&&>(real[idx]);
     156                 :             :                 break;
     157                 :             :             }
     158   [ +  +  +  + ]:     2448012 :             if (non_empty && command-- == 0) {
     159                 :             :                 /* reserve() */
     160                 :       28105 :                 size_t res_size = provider.ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_SIZE);
     161         [ +  + ]:       28105 :                 size_t old_cap = real[idx].capacity();
     162         [ +  + ]:       28105 :                 size_t old_size = real[idx].size();
     163         [ +  + ]:       28105 :                 real[idx].reserve(res_size);
     164         [ -  + ]:       28105 :                 assert(real[idx].size() == old_size);
     165   [ +  +  -  + ]:       47019 :                 assert(real[idx].capacity() == std::max(old_cap, res_size));
     166                 :             :                 break;
     167                 :             :             }
     168   [ +  +  +  + ]:     2419907 :             if (non_empty && command-- == 0) {
     169                 :             :                 /* shrink_to_fit() */
     170         [ +  - ]:       33068 :                 size_t old_size = real[idx].size();
     171         [ +  - ]:       33068 :                 real[idx].shrink_to_fit();
     172         [ -  + ]:       33068 :                 assert(real[idx].size() == old_size);
     173         [ -  + ]:       33068 :                 assert(real[idx].capacity() == old_size);
     174                 :             :                 break;
     175                 :             :             }
     176   [ +  +  +  + ]:     2386839 :             if (existing_buffer_non_full && command-- == 0) {
     177                 :             :                 /* push_back() (copying) */
     178   [ +  -  +  - ]:       52535 :                 tmp = T(rng.rand64());
     179         [ +  - ]:       52535 :                 size_t old_size = real[idx].size();
     180         [ +  - ]:       52535 :                 size_t old_cap = real[idx].capacity();
     181         [ +  - ]:       52535 :                 real[idx].push_back(*tmp);
     182         [ +  - ]:       52535 :                 sim[idx].push_back(*tmp);
     183         [ -  + ]:       52535 :                 assert(real[idx].size() == old_size + 1);
     184         [ +  + ]:       52535 :                 if (old_cap > old_size) {
     185         [ -  + ]:       34692 :                     assert(real[idx].capacity() == old_cap);
     186                 :             :                 } else {
     187         [ -  + ]:       17843 :                     assert(real[idx].capacity() > old_cap);
     188         [ -  + ]:       17843 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     189                 :             :                 }
     190                 :             :                 break;
     191                 :             :             }
     192   [ +  +  +  + ]:     2334304 :             if (existing_buffer_non_full && command-- == 0) {
     193                 :             :                 /* push_back() (moving) */
     194   [ +  -  +  - ]:       37569 :                 tmp = T(rng.rand64());
     195         [ +  - ]:       37569 :                 size_t old_size = real[idx].size();
     196         [ +  - ]:       37569 :                 size_t old_cap = real[idx].capacity();
     197         [ +  - ]:       37569 :                 sim[idx].push_back(*tmp);
     198         [ +  - ]:       37569 :                 real[idx].push_back(std::move(*tmp));
     199         [ -  + ]:       37569 :                 assert(real[idx].size() == old_size + 1);
     200         [ +  + ]:       37569 :                 if (old_cap > old_size) {
     201         [ -  + ]:       26467 :                     assert(real[idx].capacity() == old_cap);
     202                 :             :                 } else {
     203         [ -  + ]:       11102 :                     assert(real[idx].capacity() > old_cap);
     204         [ -  + ]:       11102 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     205                 :             :                 }
     206                 :             :                 break;
     207                 :             :             }
     208   [ +  +  +  + ]:     2296735 :             if (existing_buffer_non_full && command-- == 0) {
     209                 :             :                 /* emplace_back() */
     210                 :       60921 :                 uint64_t seed{rng.rand64()};
     211         [ +  - ]:       60921 :                 size_t old_size = real[idx].size();
     212         [ +  - ]:       60921 :                 size_t old_cap = real[idx].capacity();
     213         [ +  - ]:       60921 :                 sim[idx].emplace_back(seed);
     214         [ +  - ]:       60921 :                 real[idx].emplace_back(seed);
     215         [ -  + ]:       60921 :                 assert(real[idx].size() == old_size + 1);
     216         [ +  + ]:       60921 :                 if (old_cap > old_size) {
     217         [ -  + ]:       46109 :                     assert(real[idx].capacity() == old_cap);
     218                 :             :                 } else {
     219         [ -  + ]:       14812 :                     assert(real[idx].capacity() > old_cap);
     220         [ -  + ]:       14812 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     221                 :             :                 }
     222                 :             :                 break;
     223                 :             :             }
     224   [ +  +  +  + ]:     2235814 :             if (existing_buffer_non_full && command-- == 0) {
     225                 :             :                 /* push_front() (copying) */
     226   [ +  -  +  - ]:       49266 :                 tmp = T(rng.rand64());
     227         [ +  - ]:       49266 :                 size_t old_size = real[idx].size();
     228         [ +  - ]:       49266 :                 size_t old_cap = real[idx].capacity();
     229         [ +  - ]:       49266 :                 real[idx].push_front(*tmp);
     230         [ +  - ]:       49266 :                 sim[idx].push_front(*tmp);
     231         [ -  + ]:       49266 :                 assert(real[idx].size() == old_size + 1);
     232         [ +  + ]:       49266 :                 if (old_cap > old_size) {
     233         [ -  + ]:       34909 :                     assert(real[idx].capacity() == old_cap);
     234                 :             :                 } else {
     235         [ -  + ]:       14357 :                     assert(real[idx].capacity() > old_cap);
     236         [ -  + ]:       14357 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     237                 :             :                 }
     238                 :             :                 break;
     239                 :             :             }
     240   [ +  +  +  + ]:     2186548 :             if (existing_buffer_non_full && command-- == 0) {
     241                 :             :                 /* push_front() (moving) */
     242   [ +  -  +  - ]:       63343 :                 tmp = T(rng.rand64());
     243         [ +  - ]:       63343 :                 size_t old_size = real[idx].size();
     244         [ +  - ]:       63343 :                 size_t old_cap = real[idx].capacity();
     245         [ +  - ]:       63343 :                 sim[idx].push_front(*tmp);
     246         [ +  - ]:       63343 :                 real[idx].push_front(std::move(*tmp));
     247         [ -  + ]:       63343 :                 assert(real[idx].size() == old_size + 1);
     248         [ +  + ]:       63343 :                 if (old_cap > old_size) {
     249         [ -  + ]:       49371 :                     assert(real[idx].capacity() == old_cap);
     250                 :             :                 } else {
     251         [ -  + ]:       13972 :                     assert(real[idx].capacity() > old_cap);
     252         [ -  + ]:       13972 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     253                 :             :                 }
     254                 :             :                 break;
     255                 :             :             }
     256   [ +  +  +  + ]:     2123205 :             if (existing_buffer_non_full && command-- == 0) {
     257                 :             :                 /* emplace_front() */
     258                 :       93310 :                 uint64_t seed{rng.rand64()};
     259         [ +  - ]:       93310 :                 size_t old_size = real[idx].size();
     260         [ +  - ]:       93310 :                 size_t old_cap = real[idx].capacity();
     261         [ +  - ]:       93310 :                 sim[idx].emplace_front(seed);
     262         [ +  - ]:       93310 :                 real[idx].emplace_front(seed);
     263         [ -  + ]:       93310 :                 assert(real[idx].size() == old_size + 1);
     264         [ +  + ]:       93310 :                 if (old_cap > old_size) {
     265         [ -  + ]:       72891 :                     assert(real[idx].capacity() == old_cap);
     266                 :             :                 } else {
     267         [ -  + ]:       20419 :                     assert(real[idx].capacity() > old_cap);
     268         [ -  + ]:       20419 :                     assert(real[idx].capacity() <= 2 * (old_cap + 1));
     269                 :             :                 }
     270                 :             :                 break;
     271                 :             :             }
     272   [ +  +  +  + ]:     2029895 :             if (existing_buffer_non_empty && command-- == 0) {
     273                 :             :                 /* front() [modifying] */
     274   [ +  -  +  - ]:       26481 :                 tmp = T(rng.rand64());
     275                 :       26481 :                 size_t old_size = real[idx].size();
     276         [ -  + ]:       26481 :                 assert(sim[idx].front() == real[idx].front());
     277                 :       26481 :                 sim[idx].front() = *tmp;
     278                 :       26481 :                 real[idx].front() = std::move(*tmp);
     279         [ -  + ]:       26481 :                 assert(real[idx].size() == old_size);
     280                 :             :                 break;
     281                 :             :             }
     282   [ +  +  +  + ]:     2003414 :             if (existing_buffer_non_empty && command-- == 0) {
     283                 :             :                 /* back() [modifying] */
     284   [ +  -  +  - ]:       20279 :                 tmp = T(rng.rand64());
     285                 :       20279 :                 size_t old_size = real[idx].size();
     286         [ -  + ]:       20279 :                 assert(sim[idx].back() == real[idx].back());
     287                 :       20279 :                 sim[idx].back() = *tmp;
     288                 :       20279 :                 real[idx].back() = *tmp;
     289         [ -  + ]:       20279 :                 assert(real[idx].size() == old_size);
     290                 :             :                 break;
     291                 :             :             }
     292   [ +  +  +  + ]:     1983135 :             if (existing_buffer_non_empty && command-- == 0) {
     293                 :             :                 /* operator[] [modifying] */
     294   [ +  -  +  - ]:       32732 :                 tmp = T(rng.rand64());
     295                 :       46760 :                 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, sim[idx].size() - 1);
     296                 :       32732 :                 size_t old_size = real[idx].size();
     297         [ -  + ]:       32732 :                 assert(sim[idx][pos] == real[idx][pos]);
     298                 :       32732 :                 sim[idx][pos] = *tmp;
     299                 :       32732 :                 real[idx][pos] = std::move(*tmp);
     300         [ -  + ]:       32732 :                 assert(real[idx].size() == old_size);
     301                 :             :                 break;
     302                 :             :             }
     303   [ +  +  +  + ]:     1950403 :             if (existing_buffer_non_empty && command-- == 0) {
     304                 :             :                 /* pop_front() */
     305         [ -  + ]:      136374 :                 assert(sim[idx].front() == real[idx].front());
     306                 :      136374 :                 size_t old_size = real[idx].size();
     307                 :      136374 :                 sim[idx].pop_front();
     308         [ +  - ]:      136374 :                 real[idx].pop_front();
     309         [ -  + ]:      136374 :                 assert(real[idx].size() == old_size - 1);
     310                 :             :                 break;
     311                 :             :             }
     312   [ +  +  +  +  :     2550961 :             if (existing_buffer_non_empty && command-- == 0) {
                   +  + ]
     313                 :             :                 /* pop_back() */
     314         [ -  + ]:       26208 :                 assert(sim[idx].back() == real[idx].back());
     315                 :       26208 :                 size_t old_size = real[idx].size();
     316                 :       26208 :                 sim[idx].pop_back();
     317         [ +  - ]:       26208 :                 real[idx].pop_back();
     318         [ -  + ]:       26208 :                 assert(real[idx].size() == old_size - 1);
     319                 :             :                 break;
     320                 :             :             }
     321                 :             :         }
     322                 :             :     }
     323                 :             : 
     324                 :             :     /* Fully compare the final state. */
     325         [ +  + ]:        8638 :     for (unsigned i = 0; i < sim.size(); ++i) {
     326                 :             :         // Make sure const getters work.
     327                 :        6048 :         const VecDeque<T>& realbuf = real[i];
     328                 :        6048 :         const std::deque<T>& simbuf = sim[i];
     329                 :        6048 :         compare_fn(realbuf, simbuf);
     330         [ +  + ]:       22456 :         for (unsigned j = 0; j < sim.size(); ++j) {
     331         [ -  + ]:       16408 :             assert((realbuf == real[j]) == (simbuf == sim[j]));
     332         [ -  + ]:       16408 :             assert(((realbuf <=> real[j]) >= 0) == (simbuf >= sim[j]));
     333         [ -  + ]:       16408 :             assert(((realbuf <=> real[j]) <= 0) == (simbuf <= sim[j]));
     334                 :             :         }
     335                 :             :         // Clear out the buffers so we can check below that no objects exist anymore.
     336                 :        6048 :         sim[i].clear();
     337                 :        6048 :         real[i].clear();
     338                 :             :     }
     339                 :             : 
     340                 :             :     if constexpr (CheckNoneLeft) {
     341                 :        1110 :         tmp = std::nullopt;
     342                 :        1110 :         T::CheckNoneExist();
     343                 :             :     }
     344                 :        2590 : }
     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                 :             :     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                 :    20296272 :     void Check() const
     371                 :             :     {
     372                 :    20296272 :         auto it = g_tracker.find(this);
     373         [ +  + ]:   162370176 :         for (size_t i = 0; i < Size; ++i) {
     374         [ -  + ]:   142073904 :             assert(m_track_entry[i] == it);
     375                 :             :         }
     376                 :    20296272 :     }
     377                 :             : 
     378                 :             :     /** Create entry for this object in g_tracker and populate m_track_entry. */
     379                 :     4906536 :     void Register()
     380                 :             :     {
     381         [ +  - ]:     4906536 :         auto [it, inserted] = g_tracker.emplace(this, std::nullopt);
     382         [ +  - ]:     4906536 :         assert(inserted);
     383         [ +  + ]:    39252288 :         for (size_t i = 0; i < Size; ++i) {
     384                 :    34345752 :             m_track_entry[i] = it;
     385                 :             :         }
     386                 :     4906536 :     }
     387                 :             : 
     388                 :     4906536 :     void Deregister()
     389                 :             :     {
     390         [ -  + ]:     4906536 :         Check();
     391         [ -  + ]:     4906536 :         assert(m_track_entry[0] != g_tracker.end());
     392                 :     4906536 :         g_tracker.erase(m_track_entry[0]);
     393         [ +  + ]:    39252288 :         for (size_t i = 0; i < Size; ++i) {
     394                 :    34345752 :             m_track_entry[i] = g_tracker.end();
     395                 :             :         }
     396                 :     4906536 :     }
     397                 :             : 
     398                 :             :     /** Get value corresponding to this object in g_tracker. */
     399                 :     5725431 :     std::optional<uint64_t>& Deref()
     400                 :             :     {
     401         [ -  + ]:     5725431 :         Check();
     402         [ -  + ]:     5725431 :         assert(m_track_entry[0] != g_tracker.end());
     403                 :     5725431 :         return m_track_entry[0]->second;
     404                 :             :     }
     405                 :             : 
     406                 :             :     /** Get value corresponding to this object in g_tracker. */
     407                 :     9664305 :     const std::optional<uint64_t>& Deref() const
     408                 :             :     {
     409         [ -  + ]:     9664305 :         Check();
     410         [ -  + ]:     9664305 :         assert(m_track_entry[0] != g_tracker.end());
     411                 :     9664305 :         return m_track_entry[0]->second;
     412                 :             :     }
     413                 :             : 
     414                 :             : public:
     415   [ +  +  +  +  :     4906536 :     ~TrackedObj() { Deregister(); }
          +  +  +  +  +  
          +  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     416         [ +  + ]:    11563680 :     TrackedObj() { Register(); }
     417                 :             : 
     418                 :      253143 :     TrackedObj(uint64_t value)
     419         [ +  + ]:     2025144 :     {
     420                 :      253143 :         Register();
     421                 :      253143 :         Deref() = value;
     422                 :      253143 :     }
     423                 :             : 
     424                 :     2571747 :     TrackedObj(const TrackedObj& other)
     425         [ +  + ]:    20573976 :     {
     426                 :     2571747 :         Register();
     427                 :     2571747 :         Deref() = other.Deref();
     428                 :     2571747 :     }
     429                 :             : 
     430                 :      636186 :     TrackedObj(TrackedObj&& other)
     431         [ +  + ]:     5089488 :     {
     432                 :      636186 :         Register();
     433                 :      636186 :         Deref() = other.Deref();
     434         [ +  + ]:      636186 :         other.Deref() = std::nullopt;
     435                 :      636186 :     }
     436                 :             : 
     437                 :      555978 :     TrackedObj& operator=(const TrackedObj& other)
     438                 :             :     {
     439         [ +  - ]:      555978 :         if (this == &other) return *this;
     440                 :      555978 :         Deref() = other.Deref();
     441                 :      555978 :         return *this;
     442                 :             :     }
     443                 :             : 
     444                 :      145335 :     TrackedObj& operator=(TrackedObj&& other)
     445                 :             :     {
     446         [ +  - ]:      145335 :         if (this == &other) return *this;
     447                 :      145335 :         Deref() = other.Deref();
     448         [ +  - ]:      145335 :         other.Deref() = std::nullopt;
     449                 :             :         return *this;
     450                 :             :     }
     451                 :             : 
     452                 :     3093642 :     friend bool operator==(const TrackedObj& a, const TrackedObj& b)
     453                 :             :     {
     454         [ +  + ]:     3093642 :         return a.Deref() == b.Deref();
     455                 :             :     }
     456                 :             : 
     457                 :      174456 :     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   [ +  +  +  + ]:      174456 :         if (!a.Deref().has_value() || !b.Deref().has_value()) {
     462   [ +  +  +  + ]:      126060 :             return a.Deref().has_value() <=> b.Deref().has_value();
     463                 :             :         }
     464   [ +  +  +  + ]:       48396 :         return *a.Deref() <=> *b.Deref();
     465                 :             :     }
     466                 :             : 
     467         [ -  + ]:        1110 :     static void CheckNoneExist()
     468                 :             :     {
     469         [ -  + ]:        1110 :         assert(g_tracker.empty());
     470                 :        1110 :     }
     471                 :             : };
     472                 :             : 
     473                 :             : } // namespace
     474                 :             : 
     475         [ +  - ]:         782 : FUZZ_TARGET(vecdeque)
     476                 :             : {
     477                 :             :     // Run the test with simple uints (which satisfy all the trivial properties).
     478                 :         370 :     static_assert(std::is_trivially_copyable_v<uint32_t>);
     479                 :         370 :     static_assert(std::is_trivially_destructible_v<uint64_t>);
     480                 :         370 :     TestType<uint8_t, false>(buffer, 1);
     481                 :         370 :     TestType<uint16_t, false>(buffer, 2);
     482                 :         370 :     TestType<uint32_t, false>(buffer, 3);
     483                 :         370 :     TestType<uint64_t, false>(buffer, 4);
     484                 :             : 
     485                 :             :     // Run the test with TrackedObjs (which do not).
     486                 :         370 :     static_assert(!std::is_trivially_copyable_v<TrackedObj<3>>);
     487                 :         370 :     static_assert(!std::is_trivially_destructible_v<TrackedObj<17>>);
     488                 :         370 :     TestType<TrackedObj<1>, true>(buffer, 5);
     489                 :         370 :     TestType<TrackedObj<3>, true>(buffer, 6);
     490                 :         370 :     TestType<TrackedObj<17>, true>(buffer, 7);
     491                 :         370 : }
        

Generated by: LCOV version 2.0-1