Tracked down two more memory leaks coming from ext2spice, due to

client data generated by ext2spice and attached to a node's
nodeClient record;  there is an initNodeClient() routine but no
corresponding freeNodeClient() routine.  Eventually had to add a
callback function passed to EFDone() and EFFlatDone() to clean up
these entries.  After doing that, valgrind reports clean for all
memory allocated within ext2spice (there are other things that are
not freed but not related to a specific command, so do not need to
be treated as leaks).
This commit is contained in:
Tim Edwards 2021-12-13 18:05:53 -05:00
parent 7297ca079f
commit 5e3c26c95a
8 changed files with 69 additions and 20 deletions

View File

@ -638,8 +638,8 @@ runexttosim:
(void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy); (void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy);
EFVisitNodes(simnodeVisit, (ClientData) NULL); EFVisitNodes(simnodeVisit, (ClientData) NULL);
EFFlatDone(); EFFlatDone(NULL);
EFDone(); EFDone(NULL);
if (esSimF) fclose(esSimF); if (esSimF) fclose(esSimF);
if (esLabF) fclose(esLabF); if (esLabF) fclose(esLabF);
@ -766,8 +766,8 @@ main(argc, argv)
(void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy); (void) sprintf( esCapFormat, " GND %%.%dlf\n", esCapAccuracy);
EFVisitNodes(simnodeVisit, (ClientData) NULL); EFVisitNodes(simnodeVisit, (ClientData) NULL);
EFFlatDone(); EFFlatDone(NULL);
EFDone(); EFDone(NULL);
if (esSimF) fclose(esSimF); if (esSimF) fclose(esSimF);
if (esLabF) fclose(esLabF); if (esLabF) fclose(esLabF);

View File

@ -1884,7 +1884,7 @@ esHierVisit(hc, cdata)
if ((def != topdef) && (hc->hc_use->use_def->def_flags & DEF_NODEVICES) && if ((def != topdef) && (hc->hc_use->use_def->def_flags & DEF_NODEVICES) &&
(!doStub)) (!doStub))
{ {
EFFlatDone(); EFFlatDone(esFreeNodeClient);
return 0; return 0;
} }
else if (doStub) else if (doStub)
@ -1987,7 +1987,7 @@ esHierVisit(hc, cdata)
#endif #endif
} }
EFFlatDone(); EFFlatDone(esFreeNodeClient);
return 0; return 0;
} }

View File

@ -113,6 +113,34 @@ int esSpiceDevsMerged;
devMerge *devMergeList = NULL ; devMerge *devMergeList = NULL ;
/*
* ----------------------------------------------------------------------------
*
* esFreeNodeClient ---
*
* Free the string spiceNodeName associated with the nodeClient
* record that ext2spice allocates per each node structure.
*
* Returns:
* 0 always.
*
* Side effects:
* Frees an allocated string.
*
* ----------------------------------------------------------------------------
*/
int
esFreeNodeClient(client)
nodeClient *client;
{
if (client != (ClientData)NULL)
if (client->spiceNodeName != NULL)
freeMagic((char *)client->spiceNodeName);
return 0;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -1002,9 +1030,9 @@ runexttospice:
if (esFormat == HSPICE) if (esFormat == HSPICE)
printSubcktDict(); printSubcktDict();
EFFlatDone(); EFFlatDone(esFreeNodeClient);
} }
EFDone(); EFDone(esFreeNodeClient);
if (esFormat == HSPICE) { if (esFormat == HSPICE) {
HashKill(&subcktNameTable); HashKill(&subcktNameTable);
#ifndef UNSORTED_SUBCKT #ifndef UNSORTED_SUBCKT
@ -1167,8 +1195,8 @@ main(argc, argv)
if (esFormat == HSPICE) if (esFormat == HSPICE)
printSubcktDict(); printSubcktDict();
EFFlatDone(); EFFlatDone(esFreeNodeClient);
EFDone(); EFDone(esFreeNodeClient);
if (esFormat == HSPICE) { if (esFormat == HSPICE) {
HashKill(&subcktNameTable); HashKill(&subcktNameTable);
#ifndef UNSORTED_SUBCKT #ifndef UNSORTED_SUBCKT

View File

@ -36,6 +36,7 @@ extern EFNode *spcdevHierSubstrate();
extern char *nodeSpiceHierName(); extern char *nodeSpiceHierName();
extern devMerge *mkDevMerge(); extern devMerge *mkDevMerge();
extern bool extHierSDAttr(); extern bool extHierSDAttr();
extern int esFreeNodeClient();
extern bool devIsKilled(); extern bool devIsKilled();
extern float getCurDevMult(); extern float getCurDevMult();

View File

@ -1988,18 +1988,30 @@ efFreeNodeTable(table)
* Free the circular list of nodes of which 'head' is the head. * Free the circular list of nodes of which 'head' is the head.
* Don't free 'head' itself, since it's statically allocated. * Don't free 'head' itself, since it's statically allocated.
* *
* If the client (e.g., ext2spice, ext2sim, ...) allocates memory for a
* node, then that client needs to provide a function "func" of the form:
*
* int func(client)
* ClientData client;
* {
* }
*
* The return value is unused but should be zero for consistency.
*
* Results: * Results:
* None. * None.
* *
* Side effects: * Side effects:
* Frees memory. * Frees memory. Calls func() to free additional memory allocated
* in the node structure by a client.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
void void
efFreeNodeList(head) efFreeNodeList(head, func)
EFNode *head; EFNode *head;
int (*func)();
{ {
EFNode *node; EFNode *node;
EFAttr *ap; EFAttr *ap;
@ -2010,6 +2022,12 @@ efFreeNodeList(head)
{ {
for (ap = node->efnode_attrs; ap; ap = ap->efa_next) for (ap = node->efnode_attrs; ap; ap = ap->efa_next)
freeMagic((char *) ap); freeMagic((char *) ap);
if (node->efnode_client != (ClientData)NULL)
{
if (func != NULL)
(*func)(node->efnode_client);
freeMagic((char *)node->efnode_client);
}
freeMagic((char *) node); freeMagic((char *) node);
} }
} }

View File

@ -81,7 +81,7 @@ EFInit()
* *
* EFDone -- * EFDone --
* *
* Overall cleanup. * Overall cleanup. For use of func(), see efFreeNodeList() in EFbuild.c.
* *
* Results: * Results:
* None. * None.
@ -95,7 +95,8 @@ EFInit()
*/ */
void void
EFDone() EFDone(func)
int (*func)();
{ {
Connection *conn; Connection *conn;
HashSearch hs; HashSearch hs;
@ -111,7 +112,7 @@ EFDone()
def = (Def *) HashGetValue(he); def = (Def *) HashGetValue(he);
freeMagic(def->def_name); freeMagic(def->def_name);
efFreeNodeTable(&def->def_nodes); efFreeNodeTable(&def->def_nodes);
efFreeNodeList(&def->def_firstn); efFreeNodeList(&def->def_firstn, func);
efFreeUseTable(&def->def_uses); efFreeUseTable(&def->def_uses);
efFreeDevTable(&def->def_devs); efFreeDevTable(&def->def_devs);
HashKill(&def->def_nodes); HashKill(&def->def_nodes);

View File

@ -240,7 +240,7 @@ EFFlatBuildOneLevel(def, flags)
* EFFlatDone -- * EFFlatDone --
* *
* Cleanup by removing all memory used by the flattened circuit * Cleanup by removing all memory used by the flattened circuit
* representation. * representation. For use of func(), see efFreeNodeList() in EFbuild.c.
* *
* Results: * Results:
* None. * None.
@ -252,7 +252,8 @@ EFFlatBuildOneLevel(def, flags)
*/ */
void void
EFFlatDone() EFFlatDone(func)
int (*func)();
{ {
#ifdef MALLOCTRACE #ifdef MALLOCTRACE
/* Hash table statistics */ /* Hash table statistics */
@ -262,7 +263,7 @@ EFFlatDone()
/* Free temporary storage */ /* Free temporary storage */
efFreeNodeTable(&efNodeHashTable); efFreeNodeTable(&efNodeHashTable);
efFreeNodeList(&efNodeList); efFreeNodeList(&efNodeList, func);
HashFreeKill(&efCapHashTable); HashFreeKill(&efCapHashTable);
HashKill(&efNodeHashTable); HashKill(&efNodeHashTable);
HashKill(&efDistHashTable); HashKill(&efDistHashTable);

View File

@ -2172,8 +2172,8 @@ DefWriteCell(def, outName, allSpecial, units)
fprintf(f, "END NETS\n\n"); fprintf(f, "END NETS\n\n");
if (nets.has_nets) { if (nets.has_nets) {
EFFlatDone(); EFFlatDone(NULL);
EFDone(); EFDone(NULL);
} }
fprintf(f, "END DESIGN\n\n"); fprintf(f, "END DESIGN\n\n");