Plug memory leaks (#5016)

This commit is contained in:
Geza Lore 2024-03-23 22:12:43 +00:00 committed by GitHub
parent 38ad328956
commit 9b729b80e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 70 additions and 29 deletions

View File

@ -115,6 +115,7 @@ private:
AstArg* const argp = tconnect.second; AstArg* const argp = tconnect.second;
AstNode* const pinp = argp->exprp()->unlinkFrBack(); AstNode* const pinp = argp->exprp()->unlinkFrBack();
replaceVarRefsWithExprRecurse(propExprp, portp, pinp); replaceVarRefsWithExprRecurse(propExprp, portp, pinp);
VL_DO_DANGLING(pushDeletep(pinp), pinp);
} }
// Handle case with 2 disable iff statement (IEEE 1800-2023 16.12.1) // Handle case with 2 disable iff statement (IEEE 1800-2023 16.12.1)
if (nodep->disablep() && propExprp->disablep()) { if (nodep->disablep() && propExprp->disablep()) {
@ -273,12 +274,14 @@ private:
if (constp->isZero()) { if (constp->isZero()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: ##0 delays"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: ##0 delays");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
VL_DO_DANGLING(valuep->deleteTree(), valuep);
return; return;
} }
if (!m_defaultClockingp) { if (!m_defaultClockingp) {
nodep->v3error("Usage of cycle delays requires default clocking" nodep->v3error("Usage of cycle delays requires default clocking"
" (IEEE 1800-2023 14.11)"); " (IEEE 1800-2023 14.11)");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
VL_DO_DANGLING(valuep->deleteTree(), valuep);
return; return;
} }
AstEventControl* const controlp = new AstEventControl{ AstEventControl* const controlp = new AstEventControl{

View File

@ -372,7 +372,11 @@ void V3Broken::selfTest() {
// Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS // Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS
FileLine* const fl = new FileLine{FileLine::commandLineFilename()}; FileLine* const fl = new FileLine{FileLine::commandLineFilename()};
const AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr}; const AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr};
// Don't actually do it with VL_LEAK_CHECKS, when new/delete calls these.
// Otherwise you call addNewed twice on the same address, which is an error.
#ifndef VL_LEAK_CHECKS
addNewed(newp); addNewed(newp);
deleted(newp); deleted(newp);
#endif
VL_DO_DANGLING(delete newp, newp); VL_DO_DANGLING(delete newp, newp);
} }

View File

@ -53,6 +53,7 @@ class ConvertWriteRefsToRead final : public VNVisitor {
if (nodep->access().isWriteOnly()) { if (nodep->access().isWriteOnly()) {
nodep->replaceWith( nodep->replaceWith(
new AstVarRef{nodep->fileline(), nodep->varScopep(), VAccess::READ}); new AstVarRef{nodep->fileline(), nodep->varScopep(), VAccess::READ});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} }

View File

@ -1343,7 +1343,8 @@ class ConstVisitor final : public VNVisitor {
= new AstSel{nodep->fileline(), ap->unlinkFrBack(), newLsb, nodep->widthConst()}; = new AstSel{nodep->fileline(), ap->unlinkFrBack(), newLsb, nodep->widthConst()};
newp->dtypeFrom(nodep); newp->dtypeFrom(nodep);
if (debug() >= 9) newp->dumpTree("- SEL(SH)-ou: "); if (debug() >= 9) newp->dumpTree("- SEL(SH)-ou: ");
VL_DO_DANGLING(nodep->replaceWith(newp), nodep); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return true; return true;
} }
@ -1820,16 +1821,20 @@ class ConstVisitor final : public VNVisitor {
// {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR // {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR
AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop); AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop);
AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop); AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop);
AstNodeExpr* const llp = lp->lhsp()->cloneTreePure(false);
AstNodeExpr* const lrp = lp->rhsp()->cloneTreePure(false);
AstNodeExpr* const rlp = rp->lhsp()->cloneTreePure(false);
AstNodeExpr* const rrp = rp->rhsp()->cloneTreePure(false);
if (concatMergeable(lp, rp, 0)) { if (concatMergeable(lp, rp, 0)) {
AstConcat* const newlp = new AstConcat{rlp->fileline(), llp, rlp}; AstNodeExpr* const llp = lp->lhsp();
AstConcat* const newrp = new AstConcat{rrp->fileline(), lrp, rrp}; AstNodeExpr* const lrp = lp->rhsp();
AstNodeExpr* const rlp = rp->lhsp();
AstNodeExpr* const rrp = rp->rhsp();
AstConcat* const newlp = new AstConcat{rlp->fileline(), llp->cloneTreePure(false),
rlp->cloneTreePure(false)};
AstConcat* const newrp = new AstConcat{rrp->fileline(), lrp->cloneTreePure(false),
rrp->cloneTreePure(false)};
// use the lhs to replace the parent concat // use the lhs to replace the parent concat
lp->lhsp()->replaceWith(newlp); llp->replaceWith(newlp);
lp->rhsp()->replaceWith(newrp); VL_DO_DANGLING(pushDeletep(llp), llp);
lrp->replaceWith(newrp);
VL_DO_DANGLING(pushDeletep(lrp), lrp);
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), VSigning::UNSIGNED); lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), VSigning::UNSIGNED);
UINFO(5, "merged " << nodep << endl); UINFO(5, "merged " << nodep << endl);
VL_DO_DANGLING(pushDeletep(rp->unlinkFrBack()), rp); VL_DO_DANGLING(pushDeletep(rp->unlinkFrBack()), rp);

View File

@ -345,10 +345,7 @@ DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType*
dfg.addVertex(*this); dfg.addVertex(*this);
} }
DfgVertex::~DfgVertex() { DfgVertex::~DfgVertex() {}
// TODO: It would be best to intern these via AstTypeTable to save the effort
if (VN_IS(m_dtypep, UnpackArrayDType)) VL_DO_DANGLING(delete m_dtypep, m_dtypep);
}
bool DfgVertex::selfEquals(const DfgVertex& that) const { return true; } bool DfgVertex::selfEquals(const DfgVertex& that) const { return true; }

View File

@ -330,10 +330,11 @@ public:
UDEBUGONLY(UASSERT_OBJ(isSupportedDType(nodep->dtypep()), nodep, "Unsupported dtype");); UDEBUGONLY(UASSERT_OBJ(isSupportedDType(nodep->dtypep()), nodep, "Unsupported dtype"););
// For simplicity, all packed types are represented with a fixed type // For simplicity, all packed types are represented with a fixed type
if (AstUnpackArrayDType* const typep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) { if (AstUnpackArrayDType* const typep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) {
// TODO: these need interning via AstTypeTable otherwise they leak AstNodeDType* const dtypep = new AstUnpackArrayDType{
return new AstUnpackArrayDType{typep->fileline(), typep->fileline(), dtypeForWidth(typep->subDTypep()->width()),
dtypeForWidth(typep->subDTypep()->width()),
typep->rangep()->cloneTree(false)}; typep->rangep()->cloneTree(false)};
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
return dtypep;
} }
return dtypeForWidth(nodep->width()); return dtypeForWidth(nodep->width());
} }

View File

@ -294,6 +294,7 @@ void V3DfgPasses::eliminateVars(DfgGraph& dfg, V3DfgEliminateVarsContext& ctx) {
vtxp->forEachSource(addToWorkList); vtxp->forEachSource(addToWorkList);
// Remove the unused vertex // Remove the unused vertex
vtxp->unlinkDelete(dfg); vtxp->unlinkDelete(dfg);
continue;
} }
// We can only eliminate DfgVarPacked vertices at the moment // We can only eliminate DfgVarPacked vertices at the moment

View File

@ -369,8 +369,10 @@ public:
static void selfTest() { static void selfTest() {
V3Graph graph; V3Graph graph;
FileLine* const flp = v3Global.rootp()->fileline(); FileLine* const flp = v3Global.rootp()->fileline();
const auto makeBody = [flp]() { std::vector<AstMTaskBody*> mTaskBodyps;
const auto makeBody = [&]() {
AstMTaskBody* const bodyp = new AstMTaskBody{flp}; AstMTaskBody* const bodyp = new AstMTaskBody{flp};
mTaskBodyps.push_back(bodyp);
bodyp->addStmtsp(new AstComment{flp, ""}); bodyp->addStmtsp(new AstComment{flp, ""});
return bodyp; return bodyp;
}; };
@ -421,6 +423,8 @@ public:
UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t1, 1), 1130); UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t1, 1), 1130);
UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t2, 0), 1229); UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t2, 0), 1229);
UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t2, 1), 1199); UASSERT_SELFTEST(uint32_t, packer.completionTime(schedule, t2, 1), 1199);
for (AstNode* const nodep : mTaskBodyps) nodep->deleteTree();
} }
static const ThreadSchedule apply(const V3Graph& mtaskGraph) { static const ThreadSchedule apply(const V3Graph& mtaskGraph) {

View File

@ -683,7 +683,8 @@ class GateInline final {
// METHODS // METHODS
void recordSubstitution(AstVarScope* vscp, AstNodeExpr* substp, AstNode* logicp) { void recordSubstitution(AstVarScope* vscp, AstNodeExpr* substp, AstNode* logicp) {
m_hasPending.emplace(logicp, ++m_ord); // It's OK if already present m_hasPending.emplace(logicp, ++m_ord); // It's OK if already present
m_substitutions(logicp).emplace(vscp, substp->cloneTreePure(false)); const auto pair = m_substitutions(logicp).emplace(vscp, nullptr);
if (pair.second) pair.first->second = substp->cloneTreePure(false);
} }
void commitSubstitutions(AstNode* logicp) { void commitSubstitutions(AstNode* logicp) {

View File

@ -3515,6 +3515,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (AstClassRefDType* classRefp = VN_CAST(refp->skipRefp(), ClassRefDType)) { if (AstClassRefDType* classRefp = VN_CAST(refp->skipRefp(), ClassRefDType)) {
// Resolved to a class reference. // Resolved to a class reference.
refp->replaceWith(classRefp->cloneTree(false)); refp->replaceWith(classRefp->cloneTree(false));
VL_DO_DANGLING(pushDeletep(refp), refp);
} else { } else {
// Unable to resolve the ref type to a class reference. // Unable to resolve the ref type to a class reference.
// Get the value of type parameter passed to the class instance, // Get the value of type parameter passed to the class instance,

View File

@ -80,7 +80,8 @@ class LinkResolveVisitor final : public VNVisitor {
// Initial assignments under function/tasks can just be simple // Initial assignments under function/tasks can just be simple
// assignments without the initial // assignments without the initial
if (m_ftaskp) { if (m_ftaskp) {
VL_DO_DANGLING(nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext()), nodep); nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} }
void visit(AstNodeCoverOrAssert* nodep) override { void visit(AstNodeCoverOrAssert* nodep) override {

View File

@ -1275,7 +1275,7 @@ public:
if (SiblingMC* const smcp = mergeCanp->toSiblingMC()) { if (SiblingMC* const smcp = mergeCanp->toSiblingMC()) {
smcp->unlinkA(); smcp->unlinkA();
smcp->unlinkB(); smcp->unlinkB();
delete smcp; VL_DO_DANGLING(delete smcp, smcp);
} }
continue; continue;
} }
@ -1306,6 +1306,16 @@ public:
// Finally merge this candidate. // Finally merge this candidate.
contract(mergeCanp); contract(mergeCanp);
} }
// Free remaining SiblingMCs
while (MergeCandidate* const mergeCanp = m_sb.best()) {
m_sb.remove(mergeCanp);
if (SiblingMC* const smcp = mergeCanp->toSiblingMC()) {
smcp->unlinkA();
smcp->unlinkB();
VL_DO_DANGLING(delete smcp, smcp);
}
}
} }
private: private:
@ -1426,7 +1436,7 @@ private:
// Remove the siblingMC // Remove the siblingMC
mergeSibsp->unlinkA(); mergeSibsp->unlinkA();
mergeSibsp->unlinkB(); mergeSibsp->unlinkB();
VL_DO_DANGLING(delete mergeEdgep, mergeEdgep); VL_DO_DANGLING(delete mergeSibsp, mergeSibsp);
} }
// This also updates cost and stepCost on recipientp // This also updates cost and stepCost on recipientp

View File

@ -168,6 +168,11 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == VVarType::PORT) { if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == VVarType::PORT) {
// Just a port list with variable name (not v2k format); AstPort already created // Just a port list with variable name (not v2k format); AstPort already created
if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists"); if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists");
if (arrayp) VL_DO_DANGLING(arrayp->deleteTree(), arrayp);
if (attrsp) {
// TODO: Merge attributes across list? Or warn attribute is ignored
VL_DO_DANGLING(attrsp->deleteTree(), attrsp);
}
return nullptr; return nullptr;
} }
if (GRAMMARP->m_varDecl == VVarType::WREAL) { if (GRAMMARP->m_varDecl == VVarType::WREAL) {

View File

@ -462,7 +462,7 @@ class TaskVisitor final : public VNVisitor {
UINFO(9, " Port " << portp << endl); UINFO(9, " Port " << portp << endl);
UINFO(9, " pin " << pinp << endl); UINFO(9, " pin " << pinp << endl);
if (inlineTask) { if (inlineTask) {
pinp->unlinkFrBack(); // Relinked to assignment below pushDeletep(pinp->unlinkFrBack()); // Cloned in assignment below
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed
} }
if (portp->isWritable() && VN_IS(pinp, Const)) { if (portp->isWritable() && VN_IS(pinp, Const)) {
@ -490,7 +490,6 @@ class TaskVisitor final : public VNVisitor {
AstVarScope* const localVscp = varrefp->varScopep(); AstVarScope* const localVscp = varrefp->varScopep();
UASSERT_OBJ(localVscp, varrefp, "Null var scope"); UASSERT_OBJ(localVscp, varrefp, "Null var scope");
portp->user2p(localVscp); portp->user2p(localVscp);
pushDeletep(pinp);
} else { } else {
pinp->v3warn(E_TASKNSVAR, "Unsupported: ref argument of inlined " pinp->v3warn(E_TASKNSVAR, "Unsupported: ref argument of inlined "
"function/task is not a simple variable"); "function/task is not a simple variable");
@ -506,10 +505,11 @@ class TaskVisitor final : public VNVisitor {
AstVarScope* const newvscp AstVarScope* const newvscp
= createVarScope(portp, namePrefix + "__" + portp->shortName()); = createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp); portp->user2p(newvscp);
if (!inlineTask) if (!inlineTask) {
pinp->replaceWith( pinp->replaceWith(
new AstVarRef{newvscp->fileline(), newvscp, VAccess::READWRITE}); new AstVarRef{newvscp->fileline(), newvscp, VAccess::READWRITE});
pushDeletep(pinp); // Cloned by connectPortMakeInAssign
}
// Put input assignment in FRONT of all other statements // Put input assignment in FRONT of all other statements
AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, true); AstAssign* const preassp = connectPortMakeInAssign(pinp, newvscp, true);
if (AstNode* const afterp = beginp->nextp()) { if (AstNode* const afterp = beginp->nextp()) {
@ -527,8 +527,10 @@ class TaskVisitor final : public VNVisitor {
AstVarScope* const newvscp AstVarScope* const newvscp
= createVarScope(portp, namePrefix + "__" + portp->shortName()); = createVarScope(portp, namePrefix + "__" + portp->shortName());
portp->user2p(newvscp); portp->user2p(newvscp);
if (!inlineTask) if (!inlineTask) {
pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}); pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE});
pushDeletep(pinp); // Cloned by connectPortMakeOutAssign
}
AstAssign* const postassp = connectPortMakeOutAssign(portp, pinp, newvscp, false); AstAssign* const postassp = connectPortMakeOutAssign(portp, pinp, newvscp, false);
// Put assignment BEHIND of all other statements // Put assignment BEHIND of all other statements
beginp->addNext(postassp); beginp->addNext(postassp);

View File

@ -464,6 +464,7 @@ class WidthVisitor final : public VNVisitor {
void visit(AstTimeUnit* nodep) override { void visit(AstTimeUnit* nodep) override {
nodep->replaceWith( nodep->replaceWith(
new AstConst{nodep->fileline(), AstConst::Signed32{}, nodep->timeunit().powerOfTen()}); new AstConst{nodep->fileline(), AstConst::Signed32{}, nodep->timeunit().powerOfTen()});
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
void visit(AstScopeName* nodep) override { void visit(AstScopeName* nodep) override {
nodep->dtypeSetUInt64(); // A pointer, but not that it matters nodep->dtypeSetUInt64(); // A pointer, but not that it matters
@ -918,7 +919,9 @@ class WidthVisitor final : public VNVisitor {
<< nodep->msbConst() << "<" << nodep->lsbConst()); << nodep->msbConst() << "<" << nodep->lsbConst());
width = (nodep->lsbConst() - nodep->msbConst() + 1); width = (nodep->lsbConst() - nodep->msbConst() + 1);
nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED); nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED);
pushDeletep(nodep->widthp());
nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width)); nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width));
pushDeletep(nodep->lsbp());
nodep->lsbp()->replaceWith(new AstConst{nodep->lsbp()->fileline(), 0}); nodep->lsbp()->replaceWith(new AstConst{nodep->lsbp()->fileline(), 0});
} }
// We're extracting, so just make sure the expression is at least wide enough. // We're extracting, so just make sure the expression is at least wide enough.
@ -1394,7 +1397,8 @@ class WidthVisitor final : public VNVisitor {
newp->dtypeFrom(nodep); newp->dtypeFrom(nodep);
UINFO(9, "powOld " << nodep << endl); UINFO(9, "powOld " << nodep << endl);
UINFO(9, "powNew " << newp << endl); UINFO(9, "powNew " << newp << endl);
VL_DO_DANGLING(nodep->replaceWith(newp), nodep); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} }
} }
@ -1932,6 +1936,7 @@ class WidthVisitor final : public VNVisitor {
nodep->v3warn(E_UNSUPPORTED, nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Cast to " << nodep->dtp()->prettyTypeName()); "Unsupported: Cast to " << nodep->dtp()->prettyTypeName());
nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} }
} }
void visit(AstCast* nodep) override { void visit(AstCast* nodep) override {

View File

@ -5038,7 +5038,7 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
// //
// // IEEE: expression_or_dist - here to avoid reduce problems // // IEEE: expression_or_dist - here to avoid reduce problems
// // "expr yDIST '{' dist_list '}'" // // "expr yDIST '{' dist_list '}'"
| ~l~expr yDIST '{' dist_list '}' { $$ = $1; } | ~l~expr yDIST '{' dist_list '}' { $$ = $1; $4->deleteTree(); }
; ;
fexpr<nodeExprp>: // For use as first part of statement (disambiguates <=) fexpr<nodeExprp>: // For use as first part of statement (disambiguates <=)