Coverage Report

Created: 2025-07-18 07:14

/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
221k
    PointerVector() = default;
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::PointerVector()
Line
Count
Source
59
11.0k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::PointerVector()
Line
Count
Source
59
41.9k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::PointerVector()
Line
Count
Source
59
6.14k
    PointerVector() = default;
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::PointerVector()
Line
Count
Source
59
87.4k
    PointerVector() = default;
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::PointerVector()
Line
Count
Source
59
75.0k
    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
221k
    {
79
221k
      freeVectorUnsafe(m_Vector);
80
221k
    }
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::~PointerVector()
Line
Count
Source
78
11.0k
    {
79
11.0k
      freeVectorUnsafe(m_Vector);
80
11.0k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::~PointerVector()
Line
Count
Source
78
41.9k
    {
79
41.9k
      freeVectorUnsafe(m_Vector);
80
41.9k
    }
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::~PointerVector()
Line
Count
Source
78
6.14k
    {
79
6.14k
      freeVectorUnsafe(m_Vector);
80
6.14k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::~PointerVector()
Line
Count
Source
78
87.4k
    {
79
87.4k
      freeVectorUnsafe(m_Vector);
80
87.4k
    }
pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::~PointerVector()
Line
Count
Source
78
75.0k
    {
79
75.0k
      freeVectorUnsafe(m_Vector);
80
75.0k
    }
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
409k
    {
148
409k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
409k
      try
154
409k
      {
155
409k
        m_Vector.push_back(element);
156
409k
      }
157
409k
      catch (const std::exception&)
158
409k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
409k
    }
pcpp::PointerVector<pcpp::RawPacket, std::__1::default_delete<pcpp::RawPacket> >::pushBack(pcpp::RawPacket*, bool)
Line
Count
Source
147
8.82k
    {
148
8.82k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
8.82k
      try
154
8.82k
      {
155
8.82k
        m_Vector.push_back(element);
156
8.82k
      }
157
8.82k
      catch (const std::exception&)
158
8.82k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
8.82k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::pushBack(pcpp::SSLExtension*, bool)
Line
Count
Source
147
263k
    {
148
263k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
263k
      try
154
263k
      {
155
263k
        m_Vector.push_back(element);
156
263k
      }
157
263k
      catch (const std::exception&)
158
263k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
263k
    }
pcpp::PointerVector<pcpp::SSLx509Certificate, std::__1::default_delete<pcpp::SSLx509Certificate> >::pushBack(pcpp::SSLx509Certificate*, bool)
Line
Count
Source
147
16.6k
    {
148
16.6k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
16.6k
      try
154
16.6k
      {
155
16.6k
        m_Vector.push_back(element);
156
16.6k
      }
157
16.6k
      catch (const std::exception&)
158
16.6k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
16.6k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::pushBack(pcpp::SSLHandshakeMessage*, bool)
Line
Count
Source
147
119k
    {
148
119k
      if (element == nullptr)
149
0
      {
150
0
        throw std::invalid_argument("Element is nullptr");
151
0
      }
152
153
119k
      try
154
119k
      {
155
119k
        m_Vector.push_back(element);
156
119k
      }
157
119k
      catch (const std::exception&)
158
119k
      {
159
0
        if (freeElementOnError)
160
0
        {
161
0
          Deleter{}(element);
162
0
        }
163
0
        throw;
164
0
      }
165
119k
    }
Unexecuted instantiation: pcpp::PointerVector<pcpp::Asn1Record, std::__1::default_delete<pcpp::Asn1Record> >::pushBack(pcpp::Asn1Record*, bool)
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
88.7k
    {
173
88.7k
      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
88.7k
      m_Vector.push_back(element.get());
182
88.7k
      element.release();
183
88.7k
    }
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
161k
    {
217
161k
      return m_Vector.size();
218
161k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::size() const
Line
Count
Source
216
109k
    {
217
109k
      return m_Vector.size();
218
109k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::size() const
Line
Count
Source
216
50.6k
    {
217
50.6k
      return m_Vector.size();
218
50.6k
    }
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
1.12k
    {
217
1.12k
      return m_Vector.size();
218
1.12k
    }
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
8.82k
    {
239
8.82k
      return m_Vector.front();
240
8.82k
    }
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
337k
    {
320
337k
      return m_Vector.at(index);
321
337k
    }
pcpp::PointerVector<pcpp::SSLHandshakeMessage, std::__1::default_delete<pcpp::SSLHandshakeMessage> >::at(int) const
Line
Count
Source
319
87.7k
    {
320
87.7k
      return m_Vector.at(index);
321
87.7k
    }
pcpp::PointerVector<pcpp::SSLExtension, std::__1::default_delete<pcpp::SSLExtension> >::at(int) const
Line
Count
Source
319
191k
    {
320
191k
      return m_Vector.at(index);
321
191k
    }
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
59.1k
    {
320
59.1k
      return m_Vector.at(index);
321
59.1k
    }
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
221k
    {
357
221k
      for (auto& obj : origin)
358
497k
      {
359
497k
        Deleter{}(obj);
360
497k
      }
361
221k
    }
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
11.0k
    {
357
11.0k
      for (auto& obj : origin)
358
8.82k
      {
359
8.82k
        Deleter{}(obj);
360
8.82k
      }
361
11.0k
    }
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
41.9k
    {
357
41.9k
      for (auto& obj : origin)
358
263k
      {
359
263k
        Deleter{}(obj);
360
263k
      }
361
41.9k
    }
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
6.14k
    {
357
6.14k
      for (auto& obj : origin)
358
16.6k
      {
359
16.6k
        Deleter{}(obj);
360
16.6k
      }
361
6.14k
    }
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
87.4k
    {
357
87.4k
      for (auto& obj : origin)
358
119k
      {
359
119k
        Deleter{}(obj);
360
119k
      }
361
87.4k
    }
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
75.0k
    {
357
75.0k
      for (auto& obj : origin)
358
88.7k
      {
359
88.7k
        Deleter{}(obj);
360
88.7k
      }
361
75.0k
    }
362
363
    std::vector<T*> m_Vector;
364
  };
365
366
}  // namespace pcpp