From 738ee3d4eb39f36a6776977c433683ba8bfd0022 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 17 Dec 2020 02:30:58 +0900 Subject: [PATCH] Fix memory leaks when using shared protect-lib (#2707) * Guarantee mechanism to initialize just once is now in VerilatedInitializer. No functional change is intended. * Make sure to initialize Verilated::NonInitialized just once. Fixes memory leak in t_prot_lib_shared and t_hier_block_prot_lib_shared. * Call setup() and teardown() of Verilated::NonSerialized. --- include/verilated.cpp | 43 ++++++++++++++++++++++++++----------------- include/verilated.h | 6 ++++-- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index aa19b0a54..6b9afb92c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -72,10 +72,27 @@ Verilated::CommandArgValues Verilated::s_args; VerilatedImp::VerilatedImpU VerilatedImp::s_s; -struct VerilatedImpInitializer { - VerilatedImpInitializer() { VerilatedImp::setup(); } - ~VerilatedImpInitializer() { VerilatedImp::teardown(); } -} s_VerilatedImpInitializer; +// Guarantees to call setup() and teardown() just once. +struct VerilatedInitializer { + VerilatedInitializer() { setup(); } + ~VerilatedInitializer() { teardown(); } + void setup() { + static bool done = false; + if (!done) { + VerilatedImp::setup(); + Verilated::s_ns.setup(); + done = true; + } + } + void teardown() { + static bool done = false; + if (!done) { + VerilatedImp::teardown(); + Verilated::s_ns.teardown(); + done = true; + } + } +} s_VerilatedInitializer; //=========================================================================== // User definable functions @@ -261,10 +278,10 @@ Verilated::Serialized::Serialized() { s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure } -Verilated::NonSerialized::NonSerialized() { +void Verilated::NonSerialized::setup() { s_profThreadsFilenamep = strdup("profile_threads.dat"); } -Verilated::NonSerialized::~NonSerialized() { +void Verilated::NonSerialized::teardown() { if (s_profThreadsFilenamep) { VL_DO_CLEAR(free(const_cast(s_profThreadsFilenamep)), s_profThreadsFilenamep = nullptr); @@ -2478,21 +2495,13 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { // // To avoid the trouble, all member variables are enclosed in VerilatedImpU union. // ctor nor dtor of members are not called automatically. -// VerilatedImp::setup() and teardown() guarantees to initialize/destruct just once. +// VerilatedInitializer::setup() and teardown() guarantees to initialize/destruct just once. void VerilatedImp::setup() { - static bool done = false; - if (!done) { - new (&VerilatedImp::s_s) VerilatedImpData(); - done = true; - } + new (&VerilatedImp::s_s) VerilatedImpData(); } void VerilatedImp::teardown() { - static bool done = false; - if (!done) { - VerilatedImp::s_s.~VerilatedImpU(); - done = true; - } + VerilatedImp::s_s.~VerilatedImpU(); } //=========================================================================== diff --git a/include/verilated.h b/include/verilated.h index 05d25aa16..6b8dc6abc 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -399,8 +399,8 @@ class Verilated final { vluint32_t s_profThreadsWindow = 2; ///< +prof+threads window size // Slow path const char* s_profThreadsFilenamep; ///< +prof+threads filename - NonSerialized(); - ~NonSerialized(); + void setup(); + void teardown(); } s_ns; // no need to be save-restored (serialized) the @@ -429,6 +429,8 @@ class Verilated final { } t_s; private: + friend struct VerilatedInitializer; + // CONSTRUCTORS VL_UNCOPYABLE(Verilated);