Fix assignment of class reference to itself causing double free.

Test in next commit.
This commit is contained in:
Wilson Snyder 2023-11-12 07:30:56 -05:00
parent 91d0f25442
commit 30a0d62436
2 changed files with 35 additions and 23 deletions

View File

@ -284,6 +284,8 @@ inline uint64_t vl_time_stamp64() VL_MT_SAFE {
# endif
#endif
// clang-format on
uint64_t VerilatedContext::time() const VL_MT_SAFE {
// When using non-default context, fastest path is return time
if (VL_LIKELY(m_s.m_time)) return m_s.m_time;
@ -311,25 +313,6 @@ double vl_time_multiplier(int scale) VL_PURE;
// Return power of 10. e.g. returns 100 if n==2
uint64_t vl_time_pow10(int n) VL_PURE;
#ifdef VL_DEBUG
/// Evaluate statement if VL_DEBUG defined
# define VL_DEBUG_IFDEF(stmt) \
do { \
stmt \
} while (false)
/// Evaluate statement if VL_DEBUG defined and Verilated::debug() enabled
# define VL_DEBUG_IF(stmt) \
do { \
if (VL_UNLIKELY(Verilated::debug())) {stmt} \
} while (false)
#else
// We intentionally do not compile the stmt to improve compile speed
# define VL_DEBUG_IFDEF(stmt) do {} while (false)
# define VL_DEBUG_IF(stmt) do {} while (false)
#endif
// clang-format on
//=========================================================================
// Functional macros/routines
// These all take the form

View File

@ -39,6 +39,28 @@
#include <unordered_set>
#include <utility>
//=========================================================================
// Debug functions
#ifdef VL_DEBUG
/// Evaluate statement if VL_DEBUG defined
#define VL_DEBUG_IFDEF(stmt) \
do { stmt } while (false)
/// Evaluate statement if VL_DEBUG defined and Verilated::debug() enabled
#define VL_DEBUG_IF(stmt) \
do { \
if (VL_UNLIKELY(Verilated::debug())) { stmt } \
} while (false)
#else
// We intentionally do not compile the stmt to improve compile speed
#define VL_DEBUG_IFDEF(stmt) \
do { \
} while (false)
#define VL_DEBUG_IF(stmt) \
do { \
} while (false)
#endif
//===================================================================
// String formatters (required by below containers)
@ -1534,12 +1556,15 @@ class VlClass VL_NOT_FINAL : public VlDeletable {
friend class VlClassRef; // Needed for access to the ref counter and deleter
// MEMBERS
std::atomic<size_t> m_counter{0}; // Reference count for this object
std::atomic<size_t> m_counter{1}; // Reference count for this object
VlDeleter* m_deleterp = nullptr; // The deleter that will delete this object
// METHODS
// Atomically increments the reference counter
void refCountInc() VL_MT_SAFE { ++m_counter; }
void refCountInc() VL_MT_SAFE {
VL_DEBUG_IFDEF(assert(m_counter);); // If zero, we might have already deleted
++m_counter;
}
// Atomically decrements the reference counter. Assuming VlClassRef semantics are sound, it
// should never get called at m_counter == 0.
void refCountDec() VL_MT_SAFE {
@ -1548,8 +1573,8 @@ class VlClass VL_NOT_FINAL : public VlDeletable {
public:
// CONSTRUCTORS
VlClass() { refCountInc(); }
VlClass(const VlClass& copied) { refCountInc(); }
VlClass() {}
VlClass(const VlClass& copied) {}
~VlClass() override = default;
};
@ -1629,18 +1654,21 @@ public:
// METHODS
// Copy and move assignments
VlClassRef& operator=(const VlClassRef& copied) {
if (m_objp == copied.m_objp) return *this;
refCountDec();
m_objp = copied.m_objp;
refCountInc();
return *this;
}
VlClassRef& operator=(VlClassRef&& moved) {
if (m_objp == moved.m_objp) return *this;
refCountDec();
m_objp = vlstd::exchange(moved.m_objp, nullptr);
return *this;
}
template <typename T_OtherClass>
VlClassRef& operator=(const VlClassRef<T_OtherClass>& copied) {
if (m_objp == copied.m_objp) return *this;
refCountDec();
m_objp = copied.m_objp;
refCountInc();
@ -1648,6 +1676,7 @@ public:
}
template <typename T_OtherClass>
VlClassRef& operator=(VlClassRef<T_OtherClass>&& moved) {
if (m_objp == moved.m_objp) return *this;
refCountDec();
m_objp = vlstd::exchange(moved.m_objp, nullptr);
return *this;