Fix memory leaks - batch 3 (#6419)

This commit is contained in:
Geza Lore 2025-09-11 12:01:36 +01:00 committed by GitHub
parent f1396fbced
commit 56927fb955
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 112 additions and 51 deletions

View File

@ -532,6 +532,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
if (!newp) {
nodep->v3warn(NOEFFECT, "foreach with no loop variable has no effect");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
if (!bodyPointp->backp()) VL_DO_DANGLING(bodyPointp->deleteTree(), bodyPointp);
return nullptr;
}
if (bodyp) {

View File

@ -185,7 +185,10 @@ class DelayedVisitor final : public VNVisitor {
public:
VarScopeInfo() = default;
~VarScopeInfo() = default;
~VarScopeInfo() {
// Might not be linked if there was an error
if (!m_senTreep->backp()) VL_DO_DANGLING(m_senTreep->deleteTree(), m_senTreep);
}
// Accessors for the above union fields
auto& shadowVariableKit() {
UASSERT(m_scheme == Scheme::ShadowVar, "Inconsistent Scheme");
@ -932,6 +935,7 @@ class DelayedVisitor final : public VNVisitor {
AstConst* const cp = new AstConst{flp, AstConst::DTyped{}, eDTypep};
cp->num().setAllBits0();
cp->num().opSelInto(cValuep->num(), cLsbp->toSInt(), sWidth);
VL_DO_DANGLING(valuep->deleteTree(), valuep);
return cp;
}
}

View File

@ -1407,7 +1407,8 @@ class ParamVisitor final : public VNVisitor {
} else if (const AstPin* const pinp = VN_CAST(candp, Pin)) {
UINFO(9, "Found interface parameter: " << pinp);
UASSERT_OBJ(pinp->exprp(), pinp, "Interface parameter pin missing expression");
VL_DO_DANGLING(nodep->replaceWith(pinp->exprp()->cloneTree(false)), nodep);
nodep->replaceWith(pinp->exprp()->cloneTree(false));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return true;
}
}

View File

@ -78,6 +78,7 @@ void V3ParseImp::parserClear() {
// Clear up any dynamic memory V3Parser required
VARDTYPE(nullptr);
GRAMMARP->setNetDelay(nullptr);
GRAMMARP->setScopedSigAttr(nullptr);
}
//======================================================================

View File

@ -289,6 +289,7 @@ public:
void setScopedSigAttr(AstNode* attrsp) {
if (m_scopedSigAttr) { // clearing set attribute
UASSERT_OBJ(!m_scopedSigAttr->backp(), m_scopedSigAttr, "Should not link directly");
VL_DO_DANGLING(m_scopedSigAttr->deleteTree(), m_scopedSigAttr);
}
m_scopedSigAttr = attrsp;

View File

@ -1939,6 +1939,7 @@ class RandomizeVisitor final : public VNVisitor {
AstVar* const randcVarp = newRandcVarsp(memberVarp);
AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE};
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp, basicFvarp);
if (!refp->backp()) VL_DO_DANGLING(refp->deleteTree(), refp);
basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp});
}
});

View File

@ -1706,6 +1706,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp,
pinp->v3error("Duplicate argument " << argp->prettyNameQ()
<< " in function call to "
<< nodep->taskp()->prettyTypeName());
tconnects[it->second].second->unlinkFrBack()->deleteTree();
}
tconnects[it->second].second = argp;
reorganize = true;

View File

@ -179,8 +179,6 @@ class TimingSuspendableVisitor final : public VNVisitor {
// needs process metadata.
// Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_suspGraph
// Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_procGraph
const VNUser1InUse m_user1InUse;
const VNUser2InUse m_user2InUse;
const VNUser3InUse m_user3InUse;
const VNUser4InUse m_user4InUse;
@ -1259,7 +1257,11 @@ public:
void V3Timing::timingAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ":");
TimingSuspendableVisitor susVisitor{nodep};
if (v3Global.usesTiming()) TimingControlVisitor{nodep};
{
const VNUser1InUse m_user1InUse;
const VNUser2InUse m_user2InUse;
TimingSuspendableVisitor{nodep};
if (v3Global.usesTiming()) TimingControlVisitor{nodep};
}
V3Global::dumpCheckGlobalTree("timing", 0, dumpTreeEitherLevel() >= 3);
}

View File

@ -1486,6 +1486,9 @@ class TristateVisitor final : public TristateBaseVisitor {
nodep->fhsp(nonXp->cloneTreePure(true));
}
newp = new AstAdd{nodep->fileline(), nodep, newp};
} else {
// TODO: looks dubious that we still iterate this below...
pushDeletep(nodep);
}
UINFOTREE(9, newp, "", "countout");
relinkHandle.relink(newp);

View File

@ -98,6 +98,7 @@ class UdpVisitor final : public VNVisitor {
iterateChildren(nodep);
nodep->replaceWith(m_alwaysBlockp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstUdpTableLine* nodep) override {
FileLine* const fl = nodep->fileline();
@ -115,11 +116,10 @@ class UdpVisitor final : public VNVisitor {
AstLogAnd* logandp = new AstLogAnd{fl, new AstConst{fl, AstConst::BitTrue{}},
new AstConst{fl, AstConst::BitTrue{}}};
for (AstVar* itr : m_inputVars) {
for (AstVar* const varp : m_inputVars) {
if (!iNodep) break;
if (AstUdpTableLineVal* linevalp = VN_CAST(iNodep, UdpTableLineVal)) {
string valName = linevalp->name();
AstVarRef* const referencep = new AstVarRef{fl, itr, VAccess::READ};
if (isEdgeTrig(valName)) {
if (nodep->udpIsCombo()) {
linevalp->v3error(
@ -127,15 +127,18 @@ class UdpVisitor final : public VNVisitor {
}
if (edgetrigp) {
linevalp->v3error("There can be only one edge tigger signal");
VL_DO_DANGLING(pushDeletep(edgetrigp), edgetrigp);
}
edgetrigp = new AstSenTree{
fl, new AstSenItem{fl, VEdgeType::ET_BOTHEDGE,
new AstVarRef{fl, itr, VAccess::READ}}};
new AstVarRef{fl, varp, VAccess::READ}}};
}
if (valName == "0" || valName == "f") {
logandp = new AstLogAnd{
fl, logandp, new AstLogNot{fl, new AstVarRef{fl, varp, VAccess::READ}}};
} else if (valName == "1" || valName == "r") {
logandp = new AstLogAnd{fl, logandp, new AstVarRef{fl, varp, VAccess::READ}};
}
if (valName == "0" || valName == "f")
logandp = new AstLogAnd{fl, logandp, new AstLogNot{fl, referencep}};
else if (valName == "1" || valName == "r")
logandp = new AstLogAnd{fl, logandp, referencep};
}
iNodep = iNodep->nextp();
}
@ -156,11 +159,13 @@ class UdpVisitor final : public VNVisitor {
}
if (!nodep->udpIsCombo()) {
AstVarRef* const referencep = new AstVarRef{fl, m_oFieldVarp, VAccess::READ};
if (oNodep->name() == "0") {
logandp = new AstLogAnd{fl, logandp, new AstLogNot{fl, referencep}};
logandp = new AstLogAnd{
fl, logandp,
new AstLogNot{fl, new AstVarRef{fl, m_oFieldVarp, VAccess::READ}}};
} else if (oNodep->name() == "1") {
logandp = new AstLogAnd{fl, logandp, referencep};
logandp
= new AstLogAnd{fl, logandp, new AstVarRef{fl, m_oFieldVarp, VAccess::READ}};
}
}
@ -174,6 +179,7 @@ class UdpVisitor final : public VNVisitor {
oNodep->v3error("Illegal value for combinational UDP line output");
}
m_alwaysBlockp->addStmtsp(ifp);
if (edgetrigp) pushDeletep(edgetrigp);
return;
}
if (!isSequentOutputSig(oValName)) {

View File

@ -409,9 +409,14 @@ class UnknownVisitor final : public VNVisitor {
V3Number xnum{nodep, nodep->width()};
xnum.setAllBitsX();
AstNodeExpr* const xexprp = new AstConst{nodep->fileline(), xnum};
AstNodeExpr* const newp
= condp->isZero() ? xexprp
: new AstCond{nodep->fileline(), condp, nodep, xexprp};
AstNodeExpr* const newp = [&]() -> AstNodeExpr* {
if (condp->isZero()) {
VL_DO_DANGLING(condp->deleteTree(), condp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return xexprp;
}
return new AstCond{nodep->fileline(), condp, nodep, xexprp};
}();
UINFOTREE(9, newp, "", "_new");
// Link in conditional
replaceHandle.relink(newp);

View File

@ -283,6 +283,7 @@ class UnrollVisitor final : public VNVisitor {
initp->unlinkFrBack(); // Always a single statement; nextp() may be nodep
// Don't add to list, we do it once, and setting loop index isn't
// needed if we have > 1 loop, as we're constant propagating it
pushDeletep(initp); // Always cloned below.
}
if (bodysp) {
bodysp->unlinkFrBackWithNext();
@ -309,6 +310,7 @@ class UnrollVisitor final : public VNVisitor {
newbodysp = clonep;
}
if (stmtsp) {
pushDeletep(stmtsp); // Always cloned below.
int times = 0;
while (true) {
UINFO(8, " Looping " << loopValue);
@ -368,11 +370,10 @@ class UnrollVisitor final : public VNVisitor {
}
if (!newbodysp) { // initp might have effects after the loop
if (m_generate && initp) { // GENFOR(ASSIGN(...)) need to move under a new Initial
newbodysp = new AstInitial{initp->fileline(), initp};
newbodysp = new AstInitial{initp->fileline(), initp->cloneTree(true)};
} else {
newbodysp = initp; // Maybe nullptr
newbodysp = initp ? initp->cloneTree(true) : nullptr;
}
initp = nullptr;
}
// Replace the FOR()
if (newbodysp) {
@ -380,9 +381,6 @@ class UnrollVisitor final : public VNVisitor {
} else {
nodep->unlinkFrBack();
}
if (bodysp) VL_DO_DANGLING(pushDeletep(bodysp), bodysp);
if (initp) VL_DO_DANGLING(pushDeletep(initp), initp);
if (incp && !incp->backp()) VL_DO_DANGLING(pushDeletep(incp), incp);
if (newbodysp) UINFOTREE(9, newbodysp, "", "_new");
return true;
}
@ -442,6 +440,8 @@ class UnrollVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
} else {
nodep->v3error("For loop doesn't have genvar index, or is malformed");
// We will die, do it gracefully
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
}
}

View File

@ -1425,6 +1425,7 @@ class WidthVisitor final : public VNVisitor {
return;
}
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
AstAssignW* convertSetupholdToAssign(FileLine* const flp, AstNodeExpr* const evp,
@ -1434,12 +1435,20 @@ class WidthVisitor final : public VNVisitor {
UASSERT_OBJ(VN_IS(lhsp, NodeVarRef) || VN_IS(lhsp, NodePreSel), lhsp,
"Incorrect reference in a timing check");
if (AstNodeVarRef* varRefp = VN_CAST(lhsp, NodeVarRef)) {
if (varRefp->varp()->direction() == VDirection::INPUT) { return nullptr; }
if (varRefp->varp()->direction() == VDirection::INPUT) {
VL_DO_DANGLING(pushDeletep(lhsp), lhsp);
VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
return nullptr;
}
varRefp->access(VAccess::WRITE);
}
if (AstNodePreSel* selp = VN_CAST(lhsp, NodePreSel)) {
if (AstNodeVarRef* varRefp = VN_CAST(selp->fromp(), NodeVarRef)) {
if (varRefp->varp()->direction() == VDirection::INPUT) { return nullptr; }
if (varRefp->varp()->direction() == VDirection::INPUT) {
VL_DO_DANGLING(pushDeletep(lhsp), lhsp);
VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
return nullptr;
}
varRefp->access(VAccess::WRITE);
}
}
@ -3593,6 +3602,7 @@ class WidthVisitor final : public VNVisitor {
"Unsupported: enum next/prev with non-constant argument");
AstNodeExpr* const newp = new AstConst{stepp->fileline(), 1};
stepp->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(stepp), stepp);
stepp = newp;
}
const uint32_t stepWidth = VN_AS(stepp, Const)->toUInt();
@ -3609,7 +3619,7 @@ class WidthVisitor final : public VNVisitor {
return;
} else if (stepWidth != 1) {
// Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1)
nodep->pinsp()->unlinkFrBack();
pushDeletep(nodep->pinsp()->unlinkFrBack());
AstMethodCall* const clonep = nodep->cloneTree(false);
VN_AS(stepp, Const)->num().setLong(1);
AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1);
@ -5950,8 +5960,8 @@ class WidthVisitor final : public VNVisitor {
// Convert BracketArrayDType
userIterate(modVarp->childDTypep(),
WidthVP{SELF, BOTH}.p()); // May relink pointed to node
AstNodeDType* const setDtp = modVarp->childDTypep()->cloneTree(false);
if (!patternp->childDTypep()) patternp->childDTypep(setDtp);
AstNodeDType* const setDtp = modVarp->childDTypep();
if (!patternp->childDTypep()) patternp->childDTypep(setDtp->cloneTree(false));
userIterateChildren(nodep, WidthVP{setDtp, BOTH}.p());
didWidth = true;
}
@ -6538,6 +6548,7 @@ class WidthVisitor final : public VNVisitor {
nodep->v3warn(CONSTRAINTIGN, "Unsupported: std::randomize()'s 'with'");
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
VL_DO_DANGLING(pushDeletep(withp), nodep);
return;
}
processFTaskRefArgs(nodep);

View File

@ -382,9 +382,19 @@ class WidthSelVisitor final : public VNVisitor {
std::string name = (qleftBacknessp ? "sliceBackBack"
: qrightBacknessp ? "sliceFrontBack"
: "slice");
AstCMethodHard* const newp = new AstCMethodHard{
nodep->fileline(), fromp, name, qleftBacknessp ? qleftBacknessp : qleftp};
newp->addPinsp(qrightBacknessp ? qrightBacknessp : qrightp);
AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, name};
if (qleftBacknessp) {
VL_DO_DANGLING(pushDeletep(qleftp), qleftp);
newp->addPinsp(qleftBacknessp);
} else {
newp->addPinsp(qleftp);
}
if (qrightBacknessp) {
VL_DO_DANGLING(pushDeletep(qrightp), qrightp);
newp->addPinsp(qrightBacknessp);
} else {
newp->addPinsp(qrightp);
}
newp->dtypep(ddtypep);
newp->didWidth(true);
newp->protect(false);

View File

@ -142,6 +142,7 @@ const VBasicDTypeKwd LOGIC_IMPLICIT = VBasicDTypeKwd::LOGIC_IMPLICIT;
auto* const assignp = VN_AS(nodep, typeToCast); \
assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \
} \
if (!strengthSpecNodep->backp()) strengthSpecNodep->deleteTree(); \
} \
}
@ -2300,7 +2301,7 @@ enumNameRangeE<rangep>: // IEEE: second part of enum_name_declaration
/* empty */
{ $$ = nullptr; }
| '[' intnumAsConst ']'
{ $$ = new AstRange{$1, new AstConst{$1, 0}, new AstConst($1, $2->toSInt() - 1)}; }
{ $$ = new AstRange{$1, new AstConst{$1, 0}, new AstConst($1, $2->toSInt() - 1)}; DEL($2); }
| '[' intnumAsConst ':' intnumAsConst ']'
{ $$ = new AstRange{$1, $2, $4}; }
;
@ -5731,7 +5732,8 @@ specparam_assignment<varp>: // ==IEEE: specparam_assignment
if ($5) $$->valuep($5); }
| idPathpulse sigAttrListE '=' '(' minTypMax ',' minTypMax ')'
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
if ($5) $$->valuep($5); }
if ($5) $$->valuep($5);
DEL($7); }
;
system_timing_check<nodep>: // ==IEEE: system_timing_check
@ -5759,11 +5761,11 @@ timing_check_event<nodeExprp>: // ==IEEE: $timing_check_event
| yNEGEDGE terminal_identifier { $$ = $2; }
| yEDGE terminal_identifier { $$ = $2; }
| yEDGE '[' edge_descriptor_list ']' terminal_identifier { $$ = $5; }
| terminal_identifier yP_ANDANDAND expr { $$ = $1; }
| yPOSEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; }
| yNEGEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; }
| yEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; }
| yEDGE '[' edge_descriptor_list ']' terminal_identifier yP_ANDANDAND expr { $$ = $5; }
| terminal_identifier yP_ANDANDAND expr { $$ = $1; DEL($3); }
| yPOSEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; DEL($4); }
| yNEGEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; DEL($4); }
| yEDGE terminal_identifier yP_ANDANDAND expr { $$ = $2; DEL($4); }
| yEDGE '[' edge_descriptor_list ']' terminal_identifier yP_ANDANDAND expr { $$ = $5; DEL($7); }
;
edge_descriptor_list:
@ -5773,7 +5775,7 @@ edge_descriptor_list:
timing_check_limit<nodeExprp>:
expr { $$ = $1; }
| expr ':' expr ':' expr { $$ = $3; }
| expr ':' expr ':' expr { $$ = $3; DEL($1, $5); }
;
delayed_referenceE<nodeExprp>:

View File

@ -1389,6 +1389,12 @@ class VlTest:
rlimit = (softlimit, hardlimit)
resource.setrlimit(resource.RLIMIT_CPU, rlimit)
def leak_check_disable(self):
"""Disable memory leak detection when leaks are expected,
e.g.: on early abnormal termination"""
asan_options = os.environ.get("ASAN_OPTION", "")
self.setenv("ASAN_OPTION", asan_options + ":detect_leaks=0")
def execute(self, **kwargs) -> None:
"""Run simulation executable.
Arguments similar to run(); default arguments are from self"""

View File

@ -15,7 +15,7 @@ import vltest_bootstrap
test.scenarios('vlt')
os.environ["ASAN_OPTIONS"] = "detect_leaks=0"
test.leak_check_disable()
DEBUG_QUIET = "--debug --debugi 0 --gdbbt --no-dump-tree"

View File

@ -16,7 +16,7 @@ import vltest_bootstrap
test.scenarios('vlt')
test.top_filename = "t/t_a1_first_cc.v"
os.environ["ASAN_OPTIONS"] = "detect_leaks=0"
test.leak_check_disable()
DEBUG_QUIET = "--debug --debugi 0 --gdbbt --no-dump-tree"

View File

@ -11,7 +11,8 @@ import vltest_bootstrap
test.scenarios('vlt')
os.environ["ASAN_OPTIONS"] = "handle_segv=0:detect_leaks=0"
test.setenv("ASAN_OPTIONS", "handle_segv=0")
test.leak_check_disable()
test.lint(v_flags=["--debug-sigsegv"], fails=True, sanitize=0)

View File

@ -11,8 +11,7 @@ import vltest_bootstrap
test.scenarios('linter')
# Fails early in lexer, ignore leaks
os.environ["ASAN_OPTIONS"] = "detect_leaks=0"
test.leak_check_disable()
test.lint(fails=True, expect_filename=test.golden_filename)

View File

@ -12,6 +12,8 @@ import vltest_bootstrap
test.scenarios('linter')
test.top_filename = "t/t_langext_1.v"
test.leak_check_disable()
# This is a lint only test.
test.lint(v_flags2=["+verilog1995ext+v"], fails=True, expect_filename=test.golden_filename)

View File

@ -12,6 +12,8 @@ import vltest_bootstrap
test.scenarios('linter')
test.top_filename = "t/t_langext_1.v"
test.leak_check_disable()
# This is a lint only test.
test.lint(v_flags2=["+verilog1995ext+.v"], fails=True, expect_filename=test.golden_filename)

View File

@ -12,6 +12,8 @@ import vltest_bootstrap
test.scenarios('linter')
test.top_filename = "t/t_langext_2.v"
test.leak_check_disable()
# This is a lint only test.
test.lint(v_flags2=["+1364-1995ext+v"], fails=True, expect_filename=test.golden_filename)

View File

@ -12,6 +12,8 @@ import vltest_bootstrap
test.scenarios('linter')
test.top_filename = "t/t_langext_2.v"
test.leak_check_disable()
# This is a lint only test.
test.lint(v_flags2=["+1800-2005ext+v"], fails=True, expect_filename=test.golden_filename)

View File

@ -30,8 +30,4 @@
: ... note: In instance 't'
10 | for (j=0; P; j++)
| ^~~
%Error: Internal Error: t/t_param_noval_bad.v:10:7: ../V3Param.cpp:#: GENFOR should have been wrapped in BEGIN
: ... note: In instance 't'
10 | for (j=0; P; j++)
| ^~~
... This fatal error may be caused by the earlier error(s); resolve those first.
%Error: Exiting due to

View File

@ -11,6 +11,8 @@ import vltest_bootstrap
test.scenarios('linter')
test.leak_check_disable()
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()