From 5dcd3483badf71c0eec1b59f0d0adf53831f1dad Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 28 Feb 2017 00:25:43 -0600 Subject: [PATCH] dbStatic: dbPutStringNum() overflow handling Default to accepting over-size integers in DB fields, truncate to field size. E.g. permits setting DBF_LONG fields to 0xffffffff. Adds dbConvertStrict config variable to disable this. --- src/ioc/db/test/dbPutGetTest.c | 10 ++++ src/ioc/db/test/dbPutGetTest.db | 4 ++ src/ioc/dbStatic/dbStaticLib.h | 1 + src/ioc/dbStatic/dbStaticRun.c | 83 ++++++++++++++++++++++++++------- src/ioc/misc/dbCore.dbd | 1 + 5 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/ioc/db/test/dbPutGetTest.c b/src/ioc/db/test/dbPutGetTest.c index b9729940d..cd85b41d0 100644 --- a/src/ioc/db/test/dbPutGetTest.c +++ b/src/ioc/db/test/dbPutGetTest.c @@ -50,6 +50,14 @@ void testGetString(void) testdbGetStringEqual("recoverwrite.DISV", "0"); } +static +void testStringMax(void) +{ + testDiag("testStringMax()"); + + testdbGetStringEqual("recmax.DISA", "-1"); +} + void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); MAIN(dbPutGet) @@ -63,6 +71,8 @@ MAIN(dbPutGet) testGetString(); + testStringMax(); + testdbCleanup(); return testDone(); diff --git a/src/ioc/db/test/dbPutGetTest.db b/src/ioc/db/test/dbPutGetTest.db index 06a520c60..352d5aba7 100644 --- a/src/ioc/db/test/dbPutGetTest.db +++ b/src/ioc/db/test/dbPutGetTest.db @@ -29,3 +29,7 @@ record(x, "recoverwrite") { field(DISA, "") field(DISV, "") } + +record(x, "recmax") { + field(DISA, "0xffffffff") +} diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 1619a9090..4961e6236 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -244,6 +244,7 @@ epicsShareFunc void dbCatString(char **string, int *stringLength, char *pnew, char *separator); extern int dbStaticDebug; +extern int dbConvertStrict; #define S_dbLib_recordTypeNotFound (M_dbLib|1) /* Record Type does not exist */ #define S_dbLib_recExists (M_dbLib|3) /* Record Already exists */ diff --git a/src/ioc/dbStatic/dbStaticRun.c b/src/ioc/dbStatic/dbStaticRun.c index ede218cd5..236af771b 100644 --- a/src/ioc/dbStatic/dbStaticRun.c +++ b/src/ioc/dbStatic/dbStaticRun.c @@ -23,7 +23,7 @@ #include "epicsTypes.h" #include "errMdef.h" -#define epicsExportSharedSymbols +#include "epicsExport.h" /* #define epicsExportSharedSymbols */ #include "dbBase.h" #include "dbCommon.h" #include "dbStaticLib.h" @@ -31,6 +31,9 @@ #include "devSup.h" #include "special.h" +epicsShareDef int dbConvertStrict = 0; +epicsExportAddress(int, dbConvertStrict); + static long do_nothing(struct dbCommon *precord) { return 0; } /* Dummy DSXT used for soft device supports */ @@ -372,39 +375,85 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring) { dbFldDes *pflddes = pdbentry->pflddes; void *pfield = pdbentry->pfield; + long status; + epicsUInt64 u64; + epicsInt64 i64; if (!pfield) return S_dbLib_fieldNotFound; /* empty string is the same as writing numeric zero */ - if(pstring[0]=='\0') + if (pstring[0] == '\0') pstring = "0"; switch (pflddes->field_type) { case DBF_CHAR: - return epicsParseInt8(pstring, pfield, 0, NULL); - - case DBF_UCHAR: - return epicsParseUInt8(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt8(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_SHORT: - return epicsParseInt16(pstring, pfield, 0, NULL); - - case DBF_USHORT: - case DBF_ENUM: - return epicsParseUInt16(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt16(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_LONG: - return epicsParseInt32(pstring, pfield, 0, NULL); - - case DBF_ULONG: - return epicsParseUInt32(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt32(pstring, pfield, 0, NULL); + goto lax_signed; case DBF_INT64: - return epicsParseInt64(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseInt64(pstring, pfield, 0, NULL); + + lax_signed: + status = epicsParseInt64(pstring, &i64, 0, NULL); + if (status) + return status; + + switch (pflddes->field_type) { + case DBF_CHAR: *(epicsInt8 *)pfield = (epicsInt8) i64; break; + case DBF_SHORT: *(epicsInt16*)pfield = (epicsInt16)i64; break; + case DBF_LONG: *(epicsInt32*)pfield = (epicsInt32)i64; break; + case DBF_INT64: *(epicsInt64*)pfield = (epicsInt64)i64; break; + default: break; + } + return status; + + case DBF_UCHAR: + if (dbConvertStrict) + return epicsParseUInt8(pstring, pfield, 0, NULL); + goto lax_unsigned; + + case DBF_ENUM: + case DBF_USHORT: + if (dbConvertStrict) + return epicsParseUInt16(pstring, pfield, 0, NULL); + goto lax_unsigned; + + case DBF_ULONG: + if (dbConvertStrict) + return epicsParseUInt32(pstring, pfield, 0, NULL); + goto lax_unsigned; case DBF_UINT64: - return epicsParseUInt64(pstring, pfield, 0, NULL); + if (dbConvertStrict) + return epicsParseUInt64(pstring, pfield, 0, NULL); + + lax_unsigned: + status = epicsParseUInt64(pstring, &u64, 0, NULL); + if (status) + return status; + + switch (pflddes->field_type) { + case DBF_UCHAR: *(epicsUInt8 *)pfield = (epicsInt8) u64; break; + case DBF_ENUM: + case DBF_USHORT: *(epicsUInt16*)pfield = (epicsInt16)u64; break; + case DBF_ULONG: *(epicsUInt32*)pfield = (epicsInt32)u64; break; + case DBF_UINT64: *(epicsUInt64*)pfield = (epicsInt64)u64; break; + default: break; + } + return status; case DBF_FLOAT: return epicsParseFloat32(pstring, pfield, NULL); diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index a2ce45806..7349994f7 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -14,6 +14,7 @@ variable(dbRecordsOnceOnly,int) variable(dbRecordsAbcSorted,int) variable(dbBptNotMonotonic,int) variable(dbQuietMacroWarnings,int) +variable(dbConvertStrict,int) # dbLoadTemplate settings variable(dbTemplateMaxVars,int)