From 4c06cdc660f8e5642e226a0db2040cc19dd59a03 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 30 Mar 2017 17:10:52 +0200 Subject: [PATCH 01/10] Move .bzrignore to .gitignore --- .bzrignore | 9 --------- .gitignore | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) delete mode 100644 .bzrignore create mode 100644 .gitignore diff --git a/.bzrignore b/.bzrignore deleted file mode 100644 index df0e03ed6..000000000 --- a/.bzrignore +++ /dev/null @@ -1,9 +0,0 @@ -./bin -./lib -./db -./dbd -./html -./include -./templates -**/O.* -./QtC-* diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a8499e2f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/bin/ +/lib/ +/db/ +/dbd/ +/html/ +/include/ +/templates/ +O.* +/QtC-* +*.orig +*.log From 5a73ac59a19c593978f95632400c2edd9d9647de Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 31 Mar 2017 12:08:03 -0500 Subject: [PATCH 02/10] Adjusted .gitignore patterns --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a8499e2f2..c3040f162 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/cfg/ /bin/ /lib/ /db/ @@ -5,7 +6,7 @@ /html/ /include/ /templates/ -O.* +O.*/ /QtC-* *.orig *.log From 0f31e35b87b42c17a80e712697969b3ef4079924 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Apr 2017 20:25:55 -0400 Subject: [PATCH 03/10] db/test: add dbPutGetTest --- src/ioc/db/test/Makefile | 9 +++- src/ioc/db/test/dbPutGetTest.c | 79 +++++++++++++++++++++++++++++++++ src/ioc/db/test/dbPutGetTest.db | 35 +++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/ioc/db/test/dbPutGetTest.c create mode 100644 src/ioc/db/test/dbPutGetTest.db diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 3d7b340ed..215545f4a 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -131,7 +131,14 @@ recGblCheckDeadbandTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp testHarness_SRCS += recGblCheckDeadbandTest.c TESTS += recGblCheckDeadbandTest -# The testHarness runs all the test programs in a known working order. +TESTPROD_HOST += testPutGetTest +testPutGetTest_SRCS += dbPutGetTest.c +testPutGetTest_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp +testHarness_SRCS += dbPutGetTest.db +TESTFILES += ../dbPutGetTest.db +TESTS += testPutGetTest + +# This runs all the test programs in a known working order: testHarness_SRCS += epicsRunDbTests.c dbTestHarness_SRCS += $(testHarness_SRCS) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c new file mode 100644 index 000000000..5c3bbf045 --- /dev/null +++ b/src/ioc/db/test/dbPutGetTest.c @@ -0,0 +1,79 @@ + +#include + +#include +#include +#include +#include +#include + +static +void testdbGetStringEqual(const char *pv, const char *expected) +{ + const char *actual; + int ok; + DBENTRY ent; + + dbInitEntry(pdbbase, &ent); + + if(dbFindRecord(&ent, pv)) { + testFail("Failed to find record '%s'", pv); + return; + } + + actual = dbGetString(&ent); + ok = (!actual && !expected) + || (actual && expected && strcmp(actual, expected)==0); + + testOk(ok, "dbGetString(\"%s\") -> \"%s\" == \"%s\"", pv, actual, expected); + + dbFinishEntry(&ent); +} + +static +void testGetString(void) +{ + testDiag("testGetString()"); + + testdbGetStringEqual("recempty.DTYP", "Soft Channel"); + testdbGetStringEqual("recempty.DESC", ""); + testdbGetStringEqual("recempty.PHAS", "0"); + testdbGetStringEqual("recempty.TSE" , "0"); + testdbGetStringEqual("recempty.DISA", "0"); + testdbGetStringEqual("recempty.DISV", "0"); + + testdbGetStringEqual("recoverwrite.DTYP", "Soft Channel"); + testdbGetStringEqual("recoverwrite.DESC", ""); + testdbGetStringEqual("recoverwrite.PHAS", "0"); + testdbGetStringEqual("recoverwrite.TSE" , "0"); + testdbGetStringEqual("recoverwrite.DISA", "0"); + testdbGetStringEqual("recoverwrite.DISV", "0"); +} + +static +void testStringMax(void) +{ + testDiag("testStringMax()"); + + testdbGetStringEqual("recmax.DISA", "-1"); +} + +void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); + +MAIN(dbPutGet) +{ + testPlan(13); + testdbPrepare(); + + testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); + dbTestIoc_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("dbPutGetTest.db", NULL, NULL); + + testGetString(); + + testStringMax(); + + testdbCleanup(); + + return testDone(); +} diff --git a/src/ioc/db/test/dbPutGetTest.db b/src/ioc/db/test/dbPutGetTest.db new file mode 100644 index 000000000..096dbe2e4 --- /dev/null +++ b/src/ioc/db/test/dbPutGetTest.db @@ -0,0 +1,35 @@ + +record(x, "recempty") { +# empty string is the same "0" for numeric fields + field(DTYP, "") + field(DESC, "") + field(PHAS, "") + field(TSE , "") + field(DISA, "") + field(DISV, "") +} + +record(x, "recoverwrite") { +# first with non-default values +# field(DTYP, "Scan I/O") + field(DESC, "hello") + field(PHAS, "2") + field(TSE , "5") + field(DISA, "6") + field(DISV, "7") +} + +record(x, "recoverwrite") { +# now restore default values + field(DTYP, "") + field(DESC, "") + field(PHAS, "") + field(TSE , "") + field(TSEL, "") + field(DISA, "") + field(DISV, "") +} + +record(x, "recmax") { + field(DISA, "0xffffffff") +} From 8edefb9d6330a25f19db6b78249e87fe6f985748 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Apr 2017 20:27:03 -0400 Subject: [PATCH 04/10] dbUnitTest: add testdbGetArrFieldEqual() --- src/ioc/db/dbUnitTest.c | 65 +++++++++++++++++++++++++++++++++++++++++ src/ioc/db/dbUnitTest.h | 17 +++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/ioc/db/dbUnitTest.c b/src/ioc/db/dbUnitTest.c index 48d92a7fd..374a3eb51 100644 --- a/src/ioc/db/dbUnitTest.c +++ b/src/ioc/db/dbUnitTest.c @@ -190,6 +190,71 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap) } } +void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbuf) +{ + DBADDR addr; + const long vSize = dbValueSize(dbfType); + const long nStore = vSize * nRequest; + long status; + void *gbuf, *gstore; + + if(dbNameToAddr(pv, &addr)) { + testFail("Missing PV \"%s\"", pv); + return; + } + + gbuf = gstore = malloc(nStore); + if(!gbuf && nStore!=0) { /* note that malloc(0) is allowed to return NULL on success */ + testFail("Allocation failed esize=%ld total=%ld", vSize, nStore); + return; + } + + status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL); + if (status) { + testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status); + + } else { + unsigned match = nRequest==cnt; + long n, N = nRequest < cnt ? nRequest : cnt; + + if(!match) + testDiag("Length mis-match. expected=%lu actual=%lu", cnt, nRequest); + + for(n=0; n pbufcnt will detect truncation. + * nRequest < pbufcnt always fails. + * nRequest ==pbufcnt checks prefix (actual may be longer than expected) + */ +epicsShareFunc void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long pbufcnt, const void *pbuf); + epicsShareFunc dbCommon* testdbRecordPtr(const char* pv); #ifdef __cplusplus From 188825309309be74f3a4c2f26397c9ce36a806a5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 1 Apr 2017 14:24:01 -0400 Subject: [PATCH 05/10] db: fix dbGet() of link fields as DBF_CHAR dbGet() DBF_CHAR with nRequest==1 not handled correctly. Results in crash. --- src/ioc/db/dbAccess.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 6a9adb76f..a13ea566d 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -738,28 +738,34 @@ static long getLinkValue(DBADDR *paddr, short dbrType, { dbCommon *precord = paddr->precord; dbFldDes *pfldDes = paddr->pfldDes; + /* size of pbuf storage in bytes, including space for trailing nil */ int maxlen; DBENTRY dbEntry; long status; + long nReq = nRequest ? *nRequest : 1; + + /* dbFindRecord() below will always succeed as we have a + * valid DBADDR, so no point to check again. + * Request for zero elements always succeeds + */ + if(!nReq) + return 0; switch (dbrType) { case DBR_STRING: - maxlen = MAX_STRING_SIZE - 1; - if (nRequest && *nRequest > 1) *nRequest = 1; + maxlen = MAX_STRING_SIZE; + nReq = 1; break; case DBR_DOUBLE: /* Needed for dbCa links */ - if (nRequest && *nRequest) *nRequest = 1; + if (nRequest) *nRequest = 1; *(double *)pbuf = epicsNAN; return 0; case DBR_CHAR: case DBR_UCHAR: - if (nRequest && *nRequest > 0) { - maxlen = *nRequest - 1; - break; - } - /* else fall through ... */ + maxlen = nReq; + break; default: return S_db_badDbrtype; } @@ -768,10 +774,13 @@ static long getLinkValue(DBADDR *paddr, short dbrType, status = dbFindRecord(&dbEntry, precord->name); if (!status) status = dbFindField(&dbEntry, pfldDes->name); if (!status) { - char *rtnString = dbGetString(&dbEntry); + const char *rtnString = dbGetString(&dbEntry); - strncpy(pbuf, rtnString, --maxlen); - pbuf[maxlen] = 0; + strncpy(pbuf, rtnString, maxlen-1); + pbuf[maxlen-1] = 0; + if(dbrType!=DBR_STRING) + nReq = strlen(pbuf)+1; + if(nRequest) *nRequest = nReq; } dbFinishEntry(&dbEntry); return status; From fc8d4c2b5f3b50be57cdf002596469df8a42dcdc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Apr 2017 20:55:21 -0400 Subject: [PATCH 06/10] db/test: dbPutGetTest add test for lp:1678494 --- src/ioc/db/test/dbPutGetTest.c | 33 ++++++++++++++++++++++++++++++++- src/ioc/db/test/dbPutGetTest.db | 6 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c index 5c3bbf045..69cb09812 100644 --- a/src/ioc/db/test/dbPutGetTest.c +++ b/src/ioc/db/test/dbPutGetTest.c @@ -1,6 +1,7 @@ #include +#include #include #include #include @@ -58,11 +59,33 @@ void testStringMax(void) testdbGetStringEqual("recmax.DISA", "-1"); } +static +void testLongLink(void) +{ + testDiag("testLonkLink()"); + + testdbGetFieldEqual("lnktest.INP", DBR_STRING, "lnktarget NPP NMS"); + testdbGetFieldEqual("lnktest.INP$", DBR_STRING, "lnktarget NPP NMS"); + testDiag("dbGet() w/ nRequest==1 gets only trailing nil"); + testdbGetFieldEqual("lnktest.INP$", DBR_CHAR, '\0'); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 19, 18, "lnktarget NPP NMS"); + + testDiag("get w/ truncation"); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 0, 0, NULL); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 1, 1, ""); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 2, 2, "l"); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 3, 3, "ln"); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 17, 17, "lnktarget NPP NM"); + testdbGetArrFieldEqual("lnktest.INP$", DBR_CHAR, 18, 18, "lnktarget NPP NMS"); + + testdbGetArrFieldEqual("lnktest.INP", DBR_STRING, 2, 1, "lnktarget NPP NMS"); +} + void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbPutGet) { - testPlan(13); + testPlan(24); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -73,6 +96,14 @@ MAIN(dbPutGet) testStringMax(); + eltc(0); + testIocInitOk(); + eltc(1); + + testLongLink(); + + testIocShutdownOk(); + testdbCleanup(); return testDone(); diff --git a/src/ioc/db/test/dbPutGetTest.db b/src/ioc/db/test/dbPutGetTest.db index 096dbe2e4..bacaa5638 100644 --- a/src/ioc/db/test/dbPutGetTest.db +++ b/src/ioc/db/test/dbPutGetTest.db @@ -33,3 +33,9 @@ record(x, "recoverwrite") { record(x, "recmax") { field(DISA, "0xffffffff") } + +record(x, "lnktarget") {} + +record(x, "lnktest") { + field(INP, "lnktarget NPP NMS") +} From 8ebfd0821aca0a29555a119db87ddb552132c524 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Apr 2017 21:11:36 -0400 Subject: [PATCH 07/10] db: fix dbGet() for attributes as long string dbGet() of "rec.RTYP$" with DBF_CHAR and nRequest==1 not handled correctly. Results in crash. --- src/ioc/db/dbAccess.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index a13ea566d..97e9c9ad4 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -790,28 +790,31 @@ static long getAttrValue(DBADDR *paddr, short dbrType, char *pbuf, long *nRequest) { int maxlen; + long nReq = nRequest ? *nRequest : 1; if (!paddr->pfield) return S_db_badField; switch (dbrType) { case DBR_STRING: - maxlen = MAX_STRING_SIZE - 1; - if (nRequest && *nRequest > 1) *nRequest = 1; + maxlen = MAX_STRING_SIZE; + nReq = 1; break; case DBR_CHAR: case DBR_UCHAR: - if (nRequest && *nRequest > 0) { - maxlen = *nRequest - 1; - break; - } + maxlen = nReq; + break; + /* else fall through ... */ default: return S_db_badDbrtype; } - strncpy(pbuf, paddr->pfield, --maxlen); - pbuf[maxlen] = 0; + strncpy(pbuf, paddr->pfield, maxlen-1); + pbuf[maxlen-1] = 0; + if(dbrType!=DBR_STRING) + nReq = strlen(pbuf)+1; + if(nRequest) *nRequest = nReq; return 0; } From 5e082bb75d6b3f7ba49cb46bcb3e22ebc16b4cfd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Apr 2017 21:13:07 -0400 Subject: [PATCH 08/10] db/test: dbPutGetTest check for dbGet() attribute crash --- src/ioc/db/test/dbPutGetTest.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c index 69cb09812..1f3c5813d 100644 --- a/src/ioc/db/test/dbPutGetTest.c +++ b/src/ioc/db/test/dbPutGetTest.c @@ -81,11 +81,29 @@ void testLongLink(void) testdbGetArrFieldEqual("lnktest.INP", DBR_STRING, 2, 1, "lnktarget NPP NMS"); } +static +void testLongAttr(void) +{ + testDiag("testLongAttr()"); + + testdbGetFieldEqual("lnktest.RTYP", DBR_STRING, "x"); + testdbGetFieldEqual("lnktest.RTYP$", DBR_STRING, "x"); + testDiag("dbGet() w/ nRequest==1 gets only trailing nil"); + testdbGetFieldEqual("lnktest.RTYP$", DBR_CHAR, '\0'); + + testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 4, 2, "x"); + + testDiag("get w/ truncation"); + testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 0, 0, NULL); + testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 1, 1, ""); + testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 2, 2, "x"); +} + void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbPutGet) { - testPlan(24); + testPlan(31); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -101,6 +119,7 @@ MAIN(dbPutGet) eltc(1); testLongLink(); + testLongAttr(); testIocShutdownOk(); From 739a112becd12b85b2c5a184a1c9a8e8e4c45909 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Apr 2017 18:42:54 -0400 Subject: [PATCH 09/10] db: dbGet() ensure long string nil and actual string length --- src/ioc/db/dbAccess.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 97e9c9ad4..4b232b37e 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -942,6 +942,15 @@ long dbGet(DBADDR *paddr, short dbrType, localAddr.pfield = (char *) pfl->u.r.field; status = convert(&localAddr, pbuf, n, capacity, offset); } + + if(!status && dbrType==DBF_CHAR && nRequest && + paddr->pfldDes && paddr->pfldDes->field_type==DBF_STRING) + { + /* long string ensure nil and truncate to actual length */ + long nReq = *nRequest; + pbuf[nReq-1] = '\0'; + *nRequest = strlen(pbuf)+1; + } } done: paddr->pfield = pfieldsave; From b624222a0fbe47c7bf92adbe59bb5625264ce96b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Apr 2017 18:43:17 -0400 Subject: [PATCH 10/10] db/test: dbPutGetTest check dbGet() of long string field --- src/ioc/db/test/dbPutGetTest.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c index 1f3c5813d..61b31a785 100644 --- a/src/ioc/db/test/dbPutGetTest.c +++ b/src/ioc/db/test/dbPutGetTest.c @@ -99,11 +99,31 @@ void testLongAttr(void) testdbGetArrFieldEqual("lnktest.RTYP$", DBR_CHAR, 2, 2, "x"); } +static +void testLongField(void) +{ + testDiag("testLongField()"); + + testdbGetFieldEqual("lnktest.NAME", DBR_STRING, "lnktest"); + testdbGetFieldEqual("lnktest.NAME$", DBR_STRING, "108"); + testDiag("dbGet() w/ nRequest==1 gets only trailing nil"); + testdbGetFieldEqual("lnktest.NAME$", DBR_CHAR, '\0'); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 10, 8, "lnktest"); + + testDiag("get w/ truncation"); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 0, 0, NULL); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 1, 1, ""); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 2, 2, "l"); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 3, 3, "ln"); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 7, 7, "lnktes"); + testdbGetArrFieldEqual("lnktest.NAME$", DBR_CHAR, 8, 8, "lnktest"); +} + void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbPutGet) { - testPlan(31); + testPlan(41); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -120,6 +140,7 @@ MAIN(dbPutGet) testLongLink(); testLongAttr(); + testLongField(); testIocShutdownOk();