From d825f873594b1500bea61510b18d53ab57b05536 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 27 Apr 2017 12:06:54 -0500 Subject: [PATCH 1/7] Check for empty PV names in Perl catools --- src/cap5/caget.pl | 9 ++++++--- src/cap5/cainfo.pl | 7 +++++-- src/cap5/camonitor.pl | 9 ++++++--- src/cap5/caput.pl | 6 ++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/cap5/caget.pl b/src/cap5/caget.pl index a3fcbfe85..9d3df35b4 100644 --- a/src/cap5/caget.pl +++ b/src/cap5/caget.pl @@ -20,13 +20,16 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('0:ac:d:e:f:F:g:hnsStw:'); HELP_MESSAGE() if $opt_h; -die "caget: -c option takes a positive number\n" +die "caget.pl: -c option takes a positive number\n" unless looks_like_number($opt_c) && $opt_c >= 0; -die "No pv name specified. ('caget -h' gives help.)\n" +die "No pv name specified. ('caget.pl -h' gives help.)\n" unless @ARGV; -my @chans = map { CA->new($_); } @ARGV; +my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV; + +die "caget.pl: Please provide at least one non-empty pv name\n" + unless @chans; eval { CA->pend_io($opt_w); }; if ($@) { diff --git a/src/cap5/cainfo.pl b/src/cap5/cainfo.pl index 2c08bcfe6..ee6b6d0a2 100644 --- a/src/cap5/cainfo.pl +++ b/src/cap5/cainfo.pl @@ -16,10 +16,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('hw:'); HELP_MESSAGE() if $opt_h; -die "No pv name specified. ('cainfo -h' gives help.)\n" +die "No pv name specified. ('cainfo.pl -h' gives help.)\n" unless @ARGV; -my @chans = map { CA->new($_); } @ARGV; +my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV; + +die "cainfo.pl: Please provide at least one non-empty pv name\n" + unless @chans; eval { CA->pend_io($opt_w); diff --git a/src/cap5/camonitor.pl b/src/cap5/camonitor.pl index 2a933abbe..d49c85d45 100644 --- a/src/cap5/camonitor.pl +++ b/src/cap5/camonitor.pl @@ -20,14 +20,17 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('0:c:e:f:F:g:hm:nsSw:'); HELP_MESSAGE() if $opt_h; -die "caget: -c option takes a positive number\n" +die "camonitor.pl: -c option takes a positive number\n" unless looks_like_number($opt_c) && $opt_c >= 0; -die "No pv name specified. ('camonitor -h' gives help.)\n" +die "No pv name specified. ('camonitor.pl -h' gives help.)\n" unless @ARGV; my %monitors; -my @chans = map { CA->new($_, \&conn_callback); } @ARGV; +my @chans = map { CA->new($_, \&conn_callback); } grep { $_ ne '' } @ARGV; + +die "camonitor.pl: Please provide at least one non-empty pv name\n" + unless @chans; my $fmt = ($opt_F eq ' ') ? "%-30s %s\n" : "%s$opt_F%s\n"; diff --git a/src/cap5/caput.pl b/src/cap5/caput.pl index 69cd4b638..468c3ad7a 100644 --- a/src/cap5/caput.pl +++ b/src/cap5/caput.pl @@ -17,11 +17,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('achlnsStw:'); HELP_MESSAGE() if $opt_h; -die "No pv name specified. ('caput -h' gives help.)\n" +die "No pv name specified. ('caput.pl -h' gives help.)\n" unless @ARGV; my $pv = shift; +die "caput.pl: Empty pv name given.\n" + unless $pv ne ''; -die "No value specified. ('caput -h' gives help.)\n" +die "No value specified. ('caput.pl -h' gives help.)\n" unless @ARGV; my $chan = CA->new($pv); From a2ab17a7824a77450c07422854974607fe81e44a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 27 Apr 2017 16:45:22 -0400 Subject: [PATCH 2/7] libCom: STATIC_ASSERT use c++11 static_assert when possible --- src/libCom/osi/epicsAssert.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libCom/osi/epicsAssert.h b/src/libCom/osi/epicsAssert.h index e90ec9a7b..1889d642a 100644 --- a/src/libCom/osi/epicsAssert.h +++ b/src/libCom/osi/epicsAssert.h @@ -43,12 +43,15 @@ epicsShareFunc void epicsAssert (const char *pFile, const unsigned line, /* Compile-time checks */ +#if __cplusplus>=201103L +#define STATIC_ASSERT(expr) static_assert(expr, #expr) +#else #define STATIC_JOIN(x, y) STATIC_JOIN2(x, y) #define STATIC_JOIN2(x, y) x ## y #define STATIC_ASSERT(expr) \ typedef int STATIC_JOIN(static_assert_failed_at_line_, __LINE__) \ [ (expr) ? 1 : -1 ] - +#endif #ifdef __cplusplus } From 57cbe61709d3f45882b6eb55f48057321e2195c9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 27 Apr 2017 16:53:40 -0400 Subject: [PATCH 3/7] libCom/test: errlog test more verbose --- src/libCom/test/epicsErrlogTest.c | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/libCom/test/epicsErrlogTest.c b/src/libCom/test/epicsErrlogTest.c index b93bee967..3f241af95 100644 --- a/src/libCom/test/epicsErrlogTest.c +++ b/src/libCom/test/epicsErrlogTest.c @@ -75,6 +75,12 @@ typedef struct { int jam; } clientPvt; +static +void testEqInt_(int lhs, int rhs, const char *LHS, const char *RHS) +{ + testOk(lhs==rhs, "%s (%d) == %s (%d)", LHS, lhs, RHS, rhs); +} +#define testEqInt(L, R) testEqInt_(L, R, #L, #R); static void logClient(void* raw, const char* msg) { @@ -146,7 +152,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt.expect); errlogFlush(); - testOk1(pvt.count == 1); + testEqInt(pvt.count, 1); errlogAddListener(&logClient, &pvt2); @@ -156,8 +162,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt.expect); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 1); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 1); /* Removes the first listener, but the second remains */ errlogRemoveListener(&logClient); @@ -168,8 +174,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt2.expect); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 2); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 2); /* Remove the second listener */ errlogRemoveListener(&logClient); @@ -177,8 +183,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("Something different"); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 2); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 2); /* Re-add one listener */ errlogAddListener(&logClient, &pvt); @@ -191,7 +197,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", longmsg); errlogFlush(); - testOk1(pvt.count == 3); + testEqInt(pvt.count, 3); pvt.expect = NULL; @@ -204,12 +210,12 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", longmsg); epicsThreadSleep(0.1); - testOk1(pvt.count == 3); + testEqInt(pvt.count, 3); epicsEventSignal(pvt.jammer); errlogFlush(); - testOk1(pvt.count == 4); + testEqInt(pvt.count, 4); testDiag("Find buffer capacity (%u theoretical)",LOGBUFSIZE); @@ -262,7 +268,7 @@ MAIN(epicsErrlogTest) } epicsThreadSleep(0.1); /* should really be a second Event */ - testOk1(pvt.count == 0); + testEqInt(pvt.count, 0); /* Extract the first 2 messages, 2*(sizeof(msgNode) + 128) bytes */ pvt.jam = -2; @@ -270,7 +276,7 @@ MAIN(epicsErrlogTest) epicsThreadSleep(0.1); testDiag("Drained %u messages", pvt.count); - testOk1(pvt.count == 2); + testEqInt(pvt.count, 2); /* The buffer has space for 1 more message: sizeof(msgNode) + 256 bytes */ errlogPrintfNoConsole("%s", msg); /* Use up that space */ @@ -278,13 +284,13 @@ MAIN(epicsErrlogTest) testDiag("Overflow the buffer"); errlogPrintfNoConsole("%s", msg); - testOk1(pvt.count == 2); + testEqInt(pvt.count, 2); epicsEventSignal(pvt.jammer); /* Empty */ errlogFlush(); testDiag("Logged %u messages", pvt.count); - testOk1(pvt.count == N+1); + testEqInt(pvt.count, N+1); /* Clean up */ errlogRemoveListener(&logClient); From 0bf789db4cc59fcb3973ad82c20e936a3f61cdb0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Apr 2017 14:56:18 -0500 Subject: [PATCH 4/7] Fix indentation warning from GCC --- src/rec/subRecord.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rec/subRecord.c b/src/rec/subRecord.c index 22742e6fe..441755ed8 100644 --- a/src/rec/subRecord.c +++ b/src/rec/subRecord.c @@ -170,9 +170,10 @@ static long special(DBADDR *paddr, int after) subRecord *prec = (subRecord *)paddr->precord; if (!after) { - if (prec->snam[0] == 0 && prec->pact) + if (prec->snam[0] == 0 && prec->pact) { prec->pact = FALSE; prec->rpro = FALSE; + } return 0; } From dcac64d50f97c4d55a2cc023a4b5300f9e088be3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:01:39 -0400 Subject: [PATCH 5/7] ioc/dbStatic: whitespace --- src/dbStatic/dbStaticLib.c | 196 ++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 2235bac2f..f36a4606b 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -599,128 +599,128 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) dbInitEntry(pdbbase,&dbentry); pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); while(pdbRecordType) { - pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList); - while(pdbRecordNode) { - pdbRecordNodeNext = (dbRecordNode *)ellNext(&pdbRecordNode->node); - if(!dbFindRecord(&dbentry,pdbRecordNode->recordname)) - dbDeleteRecord(&dbentry); - pdbRecordNode = pdbRecordNodeNext; - } - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node); + pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList); + while(pdbRecordNode) { + pdbRecordNodeNext = (dbRecordNode *)ellNext(&pdbRecordNode->node); + if(!dbFindRecord(&dbentry,pdbRecordNode->recordname)) + dbDeleteRecord(&dbentry); + pdbRecordNode = pdbRecordNodeNext; + } + pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node); } dbFinishEntry(&dbentry); pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); while(pdbRecordType) { - for(i=0; ino_fields; i++) { - pdbFldDes = pdbRecordType->papFldDes[i]; - free((void *)pdbFldDes->prompt); - free((void *)pdbFldDes->name); - free((void *)pdbFldDes->extra); - free((void *)pdbFldDes->initial); - if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) { - dbDeviceMenu *pdbDeviceMenu; + for(i=0; ino_fields; i++) { + pdbFldDes = pdbRecordType->papFldDes[i]; + free((void *)pdbFldDes->prompt); + free((void *)pdbFldDes->name); + free((void *)pdbFldDes->extra); + free((void *)pdbFldDes->initial); + if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) { + dbDeviceMenu *pdbDeviceMenu; - pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; - free((void *)pdbDeviceMenu->papChoice); - free((void *)pdbDeviceMenu); - pdbFldDes->ftPvt=0; - } - free((void *)pdbFldDes); - } - pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); - while(pdevSup) { - pdevSupNext = (devSup *)ellNext(&pdevSup->node); - ellDelete(&pdbRecordType->devList,&pdevSup->node); - free((void *)pdevSup->name); - free((void *)pdevSup->choice); - free((void *)pdevSup); - pdevSup = pdevSupNext; - } - ptext = (dbText *)ellFirst(&pdbRecordType->cdefList); - while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbRecordType->cdefList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; - } - pAttribute = - (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList); - while(pAttribute) { - pAttributeNext = (dbRecordAttribute *)ellNext(&pAttribute->node); - ellDelete(&pdbRecordType->attributeList,&pAttribute->node); - free((void *)pAttribute->name); - free((void *)pAttribute->pdbFldDes); - pAttribute = pAttributeNext; - } - pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); - gphDelete(pdbbase->pgpHash,pdbRecordType->name,&pdbbase->recordTypeList); - ellDelete(&pdbbase->recordTypeList,&pdbRecordType->node); - free((void *)pdbRecordType->name); - free((void *)pdbRecordType->link_ind); - free((void *)pdbRecordType->papsortFldName); - free((void *)pdbRecordType->sortFldInd); - free((void *)pdbRecordType->papFldDes); - free((void *)pdbRecordType); - pdbRecordType = pdbRecordTypeNext; + pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; + free((void *)pdbDeviceMenu->papChoice); + free((void *)pdbDeviceMenu); + pdbFldDes->ftPvt=0; + } + free((void *)pdbFldDes); + } + pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); + while(pdevSup) { + pdevSupNext = (devSup *)ellNext(&pdevSup->node); + ellDelete(&pdbRecordType->devList,&pdevSup->node); + free((void *)pdevSup->name); + free((void *)pdevSup->choice); + free((void *)pdevSup); + pdevSup = pdevSupNext; + } + ptext = (dbText *)ellFirst(&pdbRecordType->cdefList); + while(ptext) { + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbRecordType->cdefList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; + } + pAttribute = + (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList); + while(pAttribute) { + pAttributeNext = (dbRecordAttribute *)ellNext(&pAttribute->node); + ellDelete(&pdbRecordType->attributeList,&pAttribute->node); + free((void *)pAttribute->name); + free((void *)pAttribute->pdbFldDes); + pAttribute = pAttributeNext; + } + pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); + gphDelete(pdbbase->pgpHash,pdbRecordType->name,&pdbbase->recordTypeList); + ellDelete(&pdbbase->recordTypeList,&pdbRecordType->node); + free((void *)pdbRecordType->name); + free((void *)pdbRecordType->link_ind); + free((void *)pdbRecordType->papsortFldName); + free((void *)pdbRecordType->sortFldInd); + free((void *)pdbRecordType->papFldDes); + free((void *)pdbRecordType); + pdbRecordType = pdbRecordTypeNext; } pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList); while(pdbMenu) { - pdbMenuNext = (dbMenu *)ellNext(&pdbMenu->node); - gphDelete(pdbbase->pgpHash,pdbMenu->name,&pdbbase->menuList); - ellDelete(&pdbbase->menuList,&pdbMenu->node); - for(i=0; i< pdbMenu->nChoice; i++) { - free((void *)pdbMenu->papChoiceName[i]); - free((void *)pdbMenu->papChoiceValue[i]); - } - free((void *)pdbMenu->papChoiceName); - free((void *)pdbMenu->papChoiceValue); - free((void *)pdbMenu ->name); - free((void *)pdbMenu); - pdbMenu = pdbMenuNext; + pdbMenuNext = (dbMenu *)ellNext(&pdbMenu->node); + gphDelete(pdbbase->pgpHash,pdbMenu->name,&pdbbase->menuList); + ellDelete(&pdbbase->menuList,&pdbMenu->node); + for(i=0; i< pdbMenu->nChoice; i++) { + free((void *)pdbMenu->papChoiceName[i]); + free((void *)pdbMenu->papChoiceValue[i]); + } + free((void *)pdbMenu->papChoiceName); + free((void *)pdbMenu->papChoiceValue); + free((void *)pdbMenu ->name); + free((void *)pdbMenu); + pdbMenu = pdbMenuNext; } pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); while(pdrvSup) { - pdrvSupNext = (drvSup *)ellNext(&pdrvSup->node); - ellDelete(&pdbbase->drvList,&pdrvSup->node); - free((void *)pdrvSup->name); - free((void *)pdrvSup); - pdrvSup = pdrvSupNext; + pdrvSupNext = (drvSup *)ellNext(&pdrvSup->node); + ellDelete(&pdbbase->drvList,&pdrvSup->node); + free((void *)pdrvSup->name); + free((void *)pdrvSup); + pdrvSup = pdrvSupNext; } ptext = (dbText *)ellFirst(&pdbbase->registrarList); while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbbase->registrarList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbbase->registrarList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; } ptext = (dbText *)ellFirst(&pdbbase->functionList); while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbbase->functionList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbbase->functionList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; } pvar = (dbVariableDef *)ellFirst(&pdbbase->variableList); while(pvar) { - pvarNext = (dbVariableDef *)ellNext(&pvar->node); - ellDelete(&pdbbase->variableList,&pvar->node); - free((void *)pvar->name); + pvarNext = (dbVariableDef *)ellNext(&pvar->node); + ellDelete(&pdbbase->variableList,&pvar->node); + free((void *)pvar->name); free((void *)pvar->type); - free((void *)pvar); - pvar = pvarNext; + free((void *)pvar); + pvar = pvarNext; } pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList); while(pbrkTable) { - pbrkTableNext = (brkTable *)ellNext(&pbrkTable->node); - gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList); - ellDelete(&pdbbase->bptList,&pbrkTable->node); - free(pbrkTable->name); - free((void *)pbrkTable->paBrkInt); - free((void *)pbrkTable); - pbrkTable = pbrkTableNext; + pbrkTableNext = (brkTable *)ellNext(&pbrkTable->node); + gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList); + ellDelete(&pdbbase->bptList,&pbrkTable->node); + free(pbrkTable->name); + free((void *)pbrkTable->paBrkInt); + free((void *)pbrkTable); + pbrkTable = pbrkTableNext; } gphFreeMem(pdbbase->pgpHash); dbPvdFreeMem(pdbbase); From 1ffce72a38dd2ece259f782dbea8fcfb74cabb5a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:02:05 -0400 Subject: [PATCH 6/7] ioc/dbStatic: plug leak in dbFreeBase() --- src/dbStatic/dbStaticLib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index f36a4606b..545f8906d 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -651,6 +651,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) ellDelete(&pdbRecordType->attributeList,&pAttribute->node); free((void *)pAttribute->name); free((void *)pAttribute->pdbFldDes); + free(pAttribute); pAttribute = pAttributeNext; } pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); From 27cd9fd0514557822f55a658c74efdd5b6fb2e4e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 17:52:58 -0400 Subject: [PATCH 7/7] ioc/dbStatic: dbFreeBase() don't double free alias'd records dbFreeBase() has been broken since alias() was introduced. Traversal of recList in the function assumed that dbDeleteRecord() remove only the current dbRecordNode. However, dbDeleteRecord() called dbDeleteAliases() which removes alias dbRecordNode s. If this happens (as it often does) to be the node immediately after the real node, dbFreeBase() will then iterate using a ellDelete()d node. --- src/dbStatic/dbStaticLib.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 545f8906d..a2ff7fc61 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -578,8 +578,6 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) dbRecordType *pdbRecordType; dbRecordType *pdbRecordTypeNext; dbFldDes * pdbFldDes; - dbRecordNode *pdbRecordNode; - dbRecordNode *pdbRecordNodeNext; dbRecordAttribute *pAttribute; dbRecordAttribute *pAttributeNext; devSup *pdevSup; @@ -594,19 +592,21 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) brkTable *pbrkTableNext; int i; DBENTRY dbentry; - + long status; dbInitEntry(pdbbase,&dbentry); - pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); - while(pdbRecordType) { - pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList); - while(pdbRecordNode) { - pdbRecordNodeNext = (dbRecordNode *)ellNext(&pdbRecordNode->node); - if(!dbFindRecord(&dbentry,pdbRecordNode->recordname)) - dbDeleteRecord(&dbentry); - pdbRecordNode = pdbRecordNodeNext; + status = dbFirstRecordType(&dbentry); + while(!status) { + /* dbDeleteRecord() will remove alias or real record node. + * For real record nodes, also removes the nodes of all aliases. + * This complicates safe traversal, so we re-start iteration + * from the first record after each call. + */ + while((status = dbFirstRecord(&dbentry))==0) { + dbDeleteRecord(&dbentry); } - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node); + assert(status==S_dbLib_recNotFound); + status = dbNextRecordType(&dbentry); } dbFinishEntry(&dbentry); pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);