Internals: Always attempt to release resources on termination (#6416)

Replace std::exit with v3Global.exit, and make V3Error::vlAbort call
v3Global.shutdown. This gives us an opportunity to release resources to
facilitate leak checking even when exiting early on an error.

Note we still don't release most resources by default without
VL_LEAK_CHECKS, so there is no behaviour change there.
This commit is contained in:
Geza Lore 2025-09-10 18:20:19 +01:00 committed by GitHub
parent d3aab31bcf
commit 57d8bb5d1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 30 deletions

View File

@ -97,19 +97,19 @@ void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) {
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
V3Error::vlAbort();
}
#ifndef V3ERROR_NO_GLOBAL_
else if (v3Global.opt.verilateJobs() > 1
&& v3Global.mainThreadId() != std::this_thread::get_id()) {
VL_GCOV_DUMP(); // No static destructors are called, thus must be called manually.
// Exit without triggering any global destructors.
// Used to prevent detached V3ThreadPool jobs accessing destroyed static objects.
#ifndef V3ERROR_NO_GLOBAL_
if (v3Global.opt.verilateJobs() > 1 && v3Global.mainThreadId() != std::this_thread::get_id()) {
// No static destructors are called, thus must be called manually.
VL_GCOV_DUMP();
// Exit without triggering any global destructors. Used to prevent
// detached V3ThreadPool jobs accessing destroyed static objects.
::_exit(1);
}
v3Global.vlExit(1);
#else
std::exit(1);
#endif
else {
std::exit(1);
}
}
string V3ErrorGuarded::warnMoreSpaces() VL_REQUIRES(m_mutex) {
@ -369,6 +369,9 @@ void V3Error::abortIfWarnings() {
void V3Error::vlAbort() {
VL_GCOV_DUMP();
#ifndef V3ERROR_NO_GLOBAL_
v3Global.shutdown();
#endif
std::abort();
}
std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex) {

View File

@ -459,12 +459,8 @@ public:
// ######################################################################
class V3Error final {
// Base class for any object that wants debugging and error reporting
// CONSTRUCTORS
V3Error() {
std::cerr << ("Static class");
V3Error::vlAbort();
}
// Static members only
V3Error() = delete;
public:
static V3ErrorGuarded& s() VL_MT_SAFE { // Singleton

View File

@ -24,6 +24,7 @@
#include "V3HierBlock.h"
#include "V3LinkCells.h"
#include "V3Parse.h"
#include "V3PreShell.h"
#include "V3Stats.h"
#include "V3ThreadPool.h"
@ -53,11 +54,18 @@ void V3Global::boot() {
}
void V3Global::shutdown() {
V3PreShell::shutdown();
VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe
VL_DO_CLEAR(delete m_threadPoolp, m_threadPoolp = nullptr); // delete nullptr is safe
#ifdef VL_LEAK_CHECKS
if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr);
#endif
FileLine::deleteAllRemaining();
}
void V3Global::vlExit(int status) {
shutdown();
std::exit(status);
}
void V3Global::checkTree() const { rootp()->checkTree(); }

View File

@ -147,6 +147,8 @@ public:
void boot();
void shutdown(); // Release allocated resources
void vlExit(int status);
// ACCESSORS (general)
AstNetlist* rootp() const VL_MT_SAFE { return m_rootp; }
V3ThreadPool* threadPoolp() const VL_PURE { return m_threadPoolp; }

View File

@ -1272,9 +1272,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
m_debugLevel[optp] = std::atoi(valp);
});
DECL_OPTION("-debug-abort", CbCall,
V3Error::vlAbort)
.undocumented(); // See also --debug-sigsegv
DECL_OPTION("-debug-abort", CbCall, []() {
V3Error::vlAbort();
}).undocumented(); // See also --debug-sigseg
DECL_OPTION("-debug-check", OnOff, &m_debugCheck);
DECL_OPTION("-debug-collision", OnOff, &m_debugCollision).undocumented();
DECL_OPTION("-debug-emitv", OnOff, &m_debugEmitV).undocumented();
@ -1392,15 +1392,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-gdbbt", CbCall, []() {}); // Processed only in bin/verilator shell
DECL_OPTION("-generate-key", CbCall, [this]() {
cout << protectKeyDefaulted() << endl;
std::exit(0);
v3Global.vlExit(0);
});
DECL_OPTION("-getenv", CbVal, [](const char* valp) {
cout << V3Options::getenvBuiltins(valp) << endl;
std::exit(0);
v3Global.vlExit(0);
});
DECL_OPTION("-get-supported", CbVal, [](const char* valp) {
cout << V3Options::getSupported(valp) << endl;
std::exit(0);
v3Global.vlExit(0);
});
DECL_OPTION("-hierarchical", OnOff, &m_hierarchical);
@ -1719,7 +1719,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
DECL_OPTION("-V", CbCall, [this]() {
showVersion(true);
std::exit(0);
v3Global.vlExit(0);
});
DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) {
V3Options::addLibraryFile(parseFileArg(optdir, valp), work());
@ -1739,7 +1739,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
});
DECL_OPTION("-version", CbCall, [this]() {
showVersion(false);
std::exit(0);
v3Global.vlExit(0);
});
DECL_OPTION("-vpi", OnOff, &m_vpi);

View File

@ -147,7 +147,7 @@ static void process() {
V3Error::abortIfErrors();
if (v3Global.opt.debugExitParse()) {
cout << "--debug-exit-parse: Exiting after parse\n";
std::exit(0);
v3Global.vlExit(0);
}
// Convert parseref's to varrefs, and other directly post parsing fixups
@ -173,7 +173,7 @@ static void process() {
V3Error::abortIfErrors();
if (v3Global.opt.serializeOnly()) emitXmlOrJson();
cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n";
std::exit(0);
v3Global.vlExit(0);
}
// Remove parameters by cloning modules to de-parameterized versions
@ -204,7 +204,7 @@ static void process() {
V3Error::abortIfErrors();
if (v3Global.opt.serializeOnly()) emitXmlOrJson();
cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n";
std::exit(0);
v3Global.vlExit(0);
}
// Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches
@ -819,7 +819,7 @@ static void execBuildJob() {
if (exit_code != 0) {
v3error(cmdStr << " exited with " << exit_code << std::endl);
std::exit(exit_code);
v3Global.vlExit(exit_code);
}
}
@ -832,7 +832,7 @@ static void execHierVerilation() {
const int exit_code = V3Os::system(cmdStr);
if (exit_code != 0) {
v3error(cmdStr << " exited with " << exit_code << std::endl);
std::exit(exit_code);
v3Global.vlExit(exit_code);
}
}
@ -884,9 +884,7 @@ int main(int argc, char** argv) {
V3DiagSarif::output(true);
// Explicitly release resources
V3PreShell::shutdown();
v3Global.shutdown();
FileLine::deleteAllRemaining();
if (!v3Global.opt.quietStats() && !v3Global.opt.preprocOnly()) {
V3Stats::addStatPerf(V3Stats::STAT_CPUTIME, cpuTimeTotal.deltaTime());