Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Common++/header/PointerVector.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <cstddef>
4
#include <cstdio>
5
#include <cstdint>
6
#include <stdexcept>
7
#include <vector>
8
#include <memory>
9
#include <type_traits>
10
11
#include "DeprecationUtils.h"
12
13
/// @file
14
15
/// @namespace pcpp
16
/// @brief The main namespace for the PcapPlusPlus lib
17
namespace pcpp
18
{
19
  namespace internal
20
  {
21
    /// @brief A helper struct to facilitate the creation of a copy of an object.
22
    /// @tparam T The type of object to copy.
23
    /// @tparam Enable Helper parameter for SFINAE.
24
    template <class T, class Enable = void> struct Copier
25
    {
26
      std::unique_ptr<T> operator()(const T& obj) const
27
      {
28
        return std::make_unique<T>(obj);
29
      }
30
    };
31
32
    /// @brief A specialization of Copier to facilitate the safe copying of polymorphic objects via clone() method.
33
    /// @tparam T The type of object to copy.
34
    template <class T> struct Copier<T, typename std::enable_if<std::is_polymorphic<T>::value>::type>
35
    {
36
      std::unique_ptr<T> operator()(const T& obj) const
37
      {
38
        // Clone can return unique_ptr or raw pointer.
39
        return std::unique_ptr<T>(std::move(obj.clone()));
40
      }
41
    };
42
  }  // namespace internal
43
44
  /// @class PointerVector
45
  /// A template class for representing a std::vector of pointers. Once (a pointer to) an element is added to this
46
  /// vector, the element responsibility moves to the vector, meaning the PointerVector will free the object once it's
47
  /// removed from the vector This class wraps std::vector and adds the capability of freeing objects once they're
48
  /// removed from it
49
  template <typename T, typename Deleter = std::default_delete<T>> class PointerVector
50
  {
51
  public:
52
    /// Iterator object that is used for iterating all elements in the vector
53
    using VectorIterator = typename std::vector<T*>::iterator;
54
55
    /// Const iterator object that is used for iterating all elements in a constant vector
56
    using ConstVectorIterator = typename std::vector<T*>::const_iterator;
57
58
    /// A constructor that create an empty instance of this object
59
113k
    PointerVector() = default;
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::PointerVector()
Line
Count
Source
59
6.06k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::PointerVector()
Line
Count
Source
59
19.5k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::PointerVector()
Line
Count
Source
59
2.07k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::PointerVector()
Line
Count
Source
59
40.0k
    PointerVector() = default;
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::PointerVector()
Line
Count
Source
59
45.8k
    PointerVector() = default;
60
61
    /// Copies the vector along with all elements inside it.
62
    /// All elements inside the copied vector are duplicates and the originals remain unchanged.
63
    /// @param[in] other The vector to copy from.
64
    /// @remarks As the vector is copied via deep copy, all pointers obtained from the copied vector
65
    /// reference the duplicates and not the originals.
66
    PointerVector(const PointerVector& other) : m_Vector(deepCopyUnsafe(other.m_Vector))
67
    {}
68
69
    /// Move constructor. All elements along with their ownership is transferred to the new vector.
70
    /// @param[in] other The vector to move from.
71
    PointerVector(PointerVector&& other) noexcept : m_Vector(std::move(other.m_Vector))
72
    {
73
      other.m_Vector.clear();
74
    }
75
76
    /// A destructor for this class. The destructor frees all elements that are binded to the vector
77
    ~PointerVector()
78
113k
    {
79
113k
      freeVectorUnsafe(m_Vector);
80
113k
    }
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::~PointerVector()
Line
Count
Source
78
6.06k
    {
79
6.06k
      freeVectorUnsafe(m_Vector);
80
6.06k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::~PointerVector()
Line
Count
Source
78
19.5k
    {
79
19.5k
      freeVectorUnsafe(m_Vector);
80
19.5k
    }
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::~PointerVector()
Line
Count
Source
78
2.07k
    {
79
2.07k
      freeVectorUnsafe(m_Vector);
80
2.07k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::~PointerVector()
Line
Count
Source
78
40.0k
    {
79
40.0k
      freeVectorUnsafe(m_Vector);
80
40.0k
    }
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::~PointerVector()
Line
Count
Source
78
45.8k
    {
79
45.8k
      freeVectorUnsafe(m_Vector);
80
45.8k
    }
81
82
    /// A copy assignment operator. Replaces the contents with a copy of the contents of other.
83
    /// See copy constructor for more information on the specific copy procedure.
84
    /// @param[in] other The vector to copy from.
85
    /// @return A reference to the current object.
86
    PointerVector& operator=(const PointerVector& other)
87
    {
88
      // Self-assignment check.
89
      if (this == &other)
90
      {
91
        return *this;
92
      }
93
94
      // Saves a copy of the old pointer to defer cleanup.
95
      auto oldValues = m_Vector;
96
      try
97
      {
98
        m_Vector = deepCopyUnsafe(other.m_Vector);
99
      }
100
      // If an exception is thrown during the copy operation, restore old values and rethrow.
101
      catch (const std::exception&)
102
      {
103
        m_Vector = std::move(oldValues);
104
        throw;
105
      }
106
      // Free old values as the new ones have been successfully assigned.
107
      freeVectorUnsafe(oldValues);
108
      return *this;
109
    }
110
111
    /// A move assignment operator. Replaces the contents with those of other via move semantics.
112
    /// The other vector is left empty.
113
    /// @param[in] other The vector to move from.
114
    /// @return A reference to the current object.
115
    PointerVector& operator=(PointerVector&& other) noexcept
116
    {
117
      if (this == &other)
118
      {
119
        return *this;
120
      }
121
122
      // Releases all current elements.
123
      clear();
124
      // Moves the elements of the other vector.
125
      m_Vector = std::move(other.m_Vector);
126
      // Explicitly clear the other vector as the standard only guarantees an unspecified valid state after move.
127
      other.m_Vector.clear();
128
      return *this;
129
    }
130
131
    /// Clears all elements of the vector while freeing them
132
    void clear()
133
    {
134
      freeVectorUnsafe(m_Vector);
135
      m_Vector.clear();
136
    }
137
138
    /// Adding a nullptr to the vector is not allowed.
139
    void pushBack(std::nullptr_t element, bool freeElementOnError = true) = delete;
140
141
    /// Add a new (pointer to an) element to the vector
142
    /// @param[in] element A pointer to an element to assume ownership of.
143
    /// @param[in] freeElementOnError If set to true, the element is freed if an exception is thrown during the
144
    /// push.
145
    /// @throws std::invalid_argument The provided pointer is a nullptr.
146
    void pushBack(T* element, bool freeElementOnError = true)
147
256k
    {
148
256k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
256k
      try
154
256k
      {
155
256k
        m_Vector.push_back(element);
156
256k
      }
157
256k
      catch (const std::exception&)
158
256k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
256k
    }
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::pushBack(pcpp::RawPacket*, bool)
Line
Count
Source
147
4.01k
    {
148
4.01k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
4.01k
      try
154
4.01k
      {
155
4.01k
        m_Vector.push_back(element);
156
4.01k
      }
157
4.01k
      catch (const std::exception&)
158
4.01k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
4.01k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::pushBack(pcpp::SSLExtension*, bool)
Line
Count
Source
147
140k
    {
148
140k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
140k
      try
154
140k
      {
155
140k
        m_Vector.push_back(element);
156
140k
      }
157
140k
      catch (const std::exception&)
158
140k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
140k
    }
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::pushBack(pcpp::SSLx509Certificate*, bool)
Line
Count
Source
147
6.38k
    {
148
6.38k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
6.38k
      try
154
6.38k
      {
155
6.38k
        m_Vector.push_back(element);
156
6.38k
      }
157
6.38k
      catch (const std::exception&)
158
6.38k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
6.38k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::pushBack(pcpp::SSLHandshakeMessage*, bool)
Line
Count
Source
147
51.4k
    {
148
51.4k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
51.4k
      try
154
51.4k
      {
155
51.4k
        m_Vector.push_back(element);
156
51.4k
      }
157
51.4k
      catch (const std::exception&)
158
51.4k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
51.4k
    }
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::pushBack(pcpp::Asn1Record*, bool)
Line
Count
Source
147
53.7k
    {
148
53.7k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
53.7k
      try
154
53.7k
      {
155
53.7k
        m_Vector.push_back(element);
156
53.7k
      }
157
53.7k
      catch (const std::exception&)
158
53.7k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
53.7k
    }
166
167
    /// Add a new element to the vector that has been managed by an unique pointer.
168
    /// @param[in] element A unique pointer holding an element.
169
    /// @throws std::invalid_argument The provided pointer is a nullptr.
170
    /// @remarks If pushBack throws the element is freed immediately.
171
    void pushBack(std::unique_ptr<T> element)
172
0
    {
173
0
      if (!element)
174
0
      {
175
0
        throw std::invalid_argument("Element is nullptr");
176
0
      }
177
178
      // Release is called after the raw pointer is already inserted into the vector to prevent
179
      // a memory leak if push_back throws.
180
      // cppcheck-suppress danglingLifetime
181
0
      m_Vector.push_back(element.get());
182
0
      element.release();
183
0
    }
184
185
    /// Get the first element of the vector
186
    /// @return An iterator object pointing to the first element of the vector
187
    VectorIterator begin()
188
0
    {
189
0
      return m_Vector.begin();
190
0
    }
191
192
    /// Get the first element of a constant vector
193
    /// @return A const iterator object pointing to the first element of the vector
194
    ConstVectorIterator begin() const
195
0
    {
196
0
      return m_Vector.begin();
197
0
    }
Unexecuted instantiation: pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::begin() const
Unexecuted instantiation: pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::begin() const
198
199
    /// Get the last element of the vector
200
    /// @return An iterator object pointing to the last element of the vector
201
    VectorIterator end()
202
0
    {
203
0
      return m_Vector.end();
204
0
    }
205
206
    /// Get the last element of a constant vector
207
    /// @return A const iterator object pointing to the last element of the vector
208
    ConstVectorIterator end() const
209
0
    {
210
0
      return m_Vector.end();
211
0
    }
Unexecuted instantiation: pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::end() const
Unexecuted instantiation: pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::end() const
212
213
    /// Get number of elements in the vector
214
    /// @return The number of elements in the vector
215
    size_t size() const
216
73.5k
    {
217
73.5k
      return m_Vector.size();
218
73.5k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::size() const
Line
Count
Source
216
48.8k
    {
217
48.8k
      return m_Vector.size();
218
48.8k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::size() const
Line
Count
Source
216
23.8k
    {
217
23.8k
      return m_Vector.size();
218
23.8k
    }
Unexecuted instantiation: pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::size() const
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::size() const
Line
Count
Source
216
910
    {
217
910
      return m_Vector.size();
218
910
    }
219
220
    /// @brief Get the current capacity of the vector.
221
    /// @return The number of elements that can be held in the vector without requiring a reallocation.
222
    size_t capacity() const
223
    {
224
      return m_Vector.capacity();
225
    }
226
227
    /// @brief Reserve storage for the vector.
228
    /// @param[in] size The number of elements to reserve space for.
229
    /// @remarks This method ensures that the vector can hold at least the specified number of elements
230
    /// without requiring a reallocation.
231
    void reserve(size_t size)
232
    {
233
      m_Vector.reserve(size);
234
    }
235
236
    /// @return A pointer of the first element in the vector
237
    T* front() const
238
4.01k
    {
239
4.01k
      return m_Vector.front();
240
4.01k
    }
241
242
    /// @return A pointer to the last element in the vector
243
    T* back() const
244
0
    {
245
0
      return m_Vector.back();
246
0
    }
247
248
    /// Removes from the vector a single element (position). Once the element is erased, it's also freed
249
    /// @param[in] position The position of the element to erase
250
    /// @return An iterator pointing to the new location of the element that followed the last element erased by the
251
    /// function call
252
    VectorIterator erase(VectorIterator position)
253
    {
254
      Deleter{}(*position);
255
      return m_Vector.erase(position);
256
    }
257
258
    /// Removes a range of elements from the vector and frees them.
259
    /// @param[in] first An iterator pointing to the first element in the range to erase.
260
    /// @param[in] last An iterator pointing to one past the last element in the range to erase.
261
    /// @return An iterator pointing to the new location of the element that followed the last element erased by the
262
    /// function call.
263
    VectorIterator erase(ConstVectorIterator first, ConstVectorIterator last)
264
    {
265
      for (auto iter = first; iter != last; ++iter)
266
      {
267
        Deleter{}(*iter);
268
      }
269
      return m_Vector.erase(first, last);
270
    }
271
272
    /// Remove an element from the vector without freeing it
273
    /// @param[in, out] position The position of the element to remove from the vector.
274
    /// The iterator is shifted to the following element after the removal is completed.
275
    /// @return A pointer to the element which is no longer managed by the vector. It's user responsibility to free
276
    /// it
277
    /// @deprecated Deprecated in favor of 'getAndDetach' as that function provides memory safety.
278
    PCPP_DEPRECATED("Please use the memory safe 'getAndDetach' instead.")
279
    T* getAndRemoveFromVector(VectorIterator& position)
280
    {
281
      T* result = *position;
282
      position = m_Vector.erase(position);
283
      return result;
284
    }
285
286
    /// Removes an element from the vector and transfers ownership to the returned unique pointer.
287
    /// @param[in] index The index of the element to detach.
288
    /// @return An unique pointer that holds ownership of the detached element.
289
    std::unique_ptr<T> getAndDetach(size_t index)
290
    {
291
      return getAndDetach(m_Vector.begin() + index);
292
    }
293
294
    /// Removes an element from the vector and transfers ownership to the returned unique pointer.
295
    /// @param[in, out] position An iterator pointing to the element to detach.
296
    /// The iterator is shifted to the following element after the detach completes.
297
    /// @return An unique pointer that holds ownership of the detached element.
298
    std::unique_ptr<T> getAndDetach(VectorIterator& position)
299
    {
300
      std::unique_ptr<T> result(*position);
301
      position = m_Vector.erase(position);
302
      return result;
303
    }
304
305
    /// Removes an element from the vector and transfers ownership to the returned unique pointer.
306
    /// @param[in] position An iterator pointing to the element to detach.
307
    /// @return An unique pointer that holds ownership of the detached element.
308
    std::unique_ptr<T> getAndDetach(const VectorIterator& position)
309
    {
310
      std::unique_ptr<T> result(*position);
311
      m_Vector.erase(position);
312
      return result;
313
    }
314
315
    /// Return a pointer to the element in a certain index
316
    /// @param[in] index The index to retrieve the element from
317
    /// @return The element at the specified position in the vector
318
    T* at(int index) const
319
173k
    {
320
173k
      return m_Vector.at(index);
321
173k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::at(int) const
Line
Count
Source
319
37.7k
    {
320
37.7k
      return m_Vector.at(index);
321
37.7k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::at(int) const
Line
Count
Source
319
98.5k
    {
320
98.5k
      return m_Vector.at(index);
321
98.5k
    }
Unexecuted instantiation: pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::at(int) const
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::at(int) const
Line
Count
Source
319
36.9k
    {
320
36.9k
      return m_Vector.at(index);
321
36.9k
    }
322
323
  private:
324
    /// Performs a copy of the vector along with its elements.
325
    /// The caller is responsible of freeing the copied elements.
326
    /// @return A vector of pointers to the newly copied elements.
327
    static std::vector<T*> deepCopyUnsafe(const std::vector<T*>& origin)
328
    {
329
      std::vector<T*> copyVec;
330
      // Allocate the vector initially to ensure no exceptions are thrown during push_back.
331
      copyVec.reserve(origin.size());
332
333
      try
334
      {
335
        for (const auto iter : origin)
336
        {
337
          std::unique_ptr<T> objCopy = internal::Copier<T>()(*iter);
338
          // There shouldn't be a memory leak as the vector is reserved.
339
          copyVec.push_back(objCopy.release());
340
        }
341
      }
342
      catch (const std::exception&)
343
      {
344
        freeVectorUnsafe(copyVec);
345
        throw;
346
      }
347
348
      return copyVec;
349
    }
350
351
    /// Frees all elements inside the vector.
352
    /// Calling this function with non-heap allocated pointers is UB.
353
    /// @param[in] origin The vector of elements to free.
354
    /// @remarks The vector's contents are not cleared and will point to invalid locations in memory.
355
    static void freeVectorUnsafe(const std::vector<T*>& origin)
356
113k
    {
357
113k
      for (auto& obj : origin)
358
256k
      {
359
256k
        Deleter{}(obj);
360
256k
      }
361
113k
    }
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::freeVectorUnsafe(std::__1::vector<pcpp::RawPacket*, std::__1::allocator<pcpp::RawPacket*> > const&)
Line
Count
Source
356
6.06k
    {
357
6.06k
      for (auto& obj : origin)
358
4.01k
      {
359
4.01k
        Deleter{}(obj);
360
4.01k
      }
361
6.06k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::freeVectorUnsafe(std::__1::vector<pcpp::SSLExtension*, std::__1::allocator<pcpp::SSLExtension*> > const&)
Line
Count
Source
356
19.5k
    {
357
19.5k
      for (auto& obj : origin)
358
140k
      {
359
140k
        Deleter{}(obj);
360
140k
      }
361
19.5k
    }
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::freeVectorUnsafe(std::__1::vector<pcpp::SSLx509Certificate*, std::__1::allocator<pcpp::SSLx509Certificate*> > const&)
Line
Count
Source
356
2.07k
    {
357
2.07k
      for (auto& obj : origin)
358
6.38k
      {
359
6.38k
        Deleter{}(obj);
360
6.38k
      }
361
2.07k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::freeVectorUnsafe(std::__1::vector<pcpp::SSLHandshakeMessage*, std::__1::allocator<pcpp::SSLHandshakeMessage*> > const&)
Line
Count
Source
356
40.0k
    {
357
40.0k
      for (auto& obj : origin)
358
51.4k
      {
359
51.4k
        Deleter{}(obj);
360
51.4k
      }
361
40.0k
    }
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::freeVectorUnsafe(std::__1::vector<pcpp::Asn1Record*, std::__1::allocator<pcpp::Asn1Record*> > const&)
Line
Count
Source
356
45.8k
    {
357
45.8k
      for (auto& obj : origin)
358
53.7k
      {
359
53.7k
        Deleter{}(obj);
360
53.7k
      }
361
45.8k
    }
362
363
    std::vector<T*> m_Vector;
364
  };
365
366
}  // namespace pcpp