From da9982f875601e4477ebb4e3348611696846f051 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 30 Jun 2012 15:34:29 -0500 Subject: [PATCH] libCom: Fix unsigned overflow limits in epicsParse* The strtoul() routine accepts negative numbers. This fix ensures we handle them properly, and adds suitable tests. Also fix the test for 1e300, in case the compiler gives a slightly different literal constant than strtod() returns. --- src/libCom/misc/epicsStdlib.c | 6 +++--- src/libCom/test/epicsStdlibTest.c | 24 +++++++++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/libCom/misc/epicsStdlib.c b/src/libCom/misc/epicsStdlib.c index 2ddb521b3..faf6ca75c 100644 --- a/src/libCom/misc/epicsStdlib.c +++ b/src/libCom/misc/epicsStdlib.c @@ -142,7 +142,7 @@ epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units) if (status) return status; - if (value > 0xff) + if (value > 0xff && value <= ~0xffUL) return S_stdlib_overflow; *to = value; @@ -174,7 +174,7 @@ epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units) if (status) return status; - if (value > 0xffff) + if (value > 0xffff && value <= ~0xffffUL) return S_stdlib_overflow; *to = value; @@ -209,7 +209,7 @@ epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units) return status; #if (ULONG_MAX > 0xffffffff) - if (value > 0xffffffffUL) + if (value > 0xffffffffUL && value <= ~0xffffffffUL) return S_stdlib_overflow; #endif diff --git a/src/libCom/test/epicsStdlibTest.c b/src/libCom/test/epicsStdlibTest.c index aa8d58f49..4f71055b0 100644 --- a/src/libCom/test/epicsStdlibTest.c +++ b/src/libCom/test/epicsStdlibTest.c @@ -14,6 +14,7 @@ #include #include +#include "epicsTypes.h" #include "epicsStdlib.h" #include "epicsMath.h" #include "epicsUnitTest.h" @@ -67,7 +68,7 @@ MAIN(epicsStdlibTest) epicsInt32 i32; epicsUInt32 u32; - testPlan(143); + testPlan(153); testOk(epicsParseLong("", &l, 0, NULL) == S_stdlib_noConversion, "Long '' => noConversion"); @@ -106,6 +107,11 @@ MAIN(epicsStdlibTest) testOk(epicsScanFloat("\t 1\n", &f) && f == 1, "Float '\\t 1\\n'"); testOk(epicsScanDouble("\t 1\n", &d) && d == 1, "Double '\\t 1\\n'"); + testOk(epicsScanLong("-1", &l, 0) && l == -1, "Long '-1'"); + testOk(epicsScanULong("-1", &u, 0) && u + 1 == 0, "ULong '-1'"); + testOk(epicsScanFloat("-1", &f) && f == -1, "Float '-1'"); + testOk(epicsScanDouble("-1", &d) && d == -1, "Double '-1'"); + testOk(epicsParseLong("2!", &l, 0, NULL) == S_stdlib_extraneous, "Long '2!' => extraneous"); testOk(epicsParseULong("2!", &u, 0, NULL) == S_stdlib_extraneous, @@ -209,16 +215,20 @@ MAIN(epicsStdlibTest) testOk(!epicsParseInt8("0x7f", &i8, 0, NULL) && i8 == 0x7f, "Int8 '0x7f'"); - testOk(!epicsParseInt8("-0x80", &i8, 0, NULL) && i8 == -0x80, + testOk(!epicsParseInt8("-0x80", &i8, 0, NULL) && ((i8 + 0x80) & 0xff) == 0, "Int8 '-0x80'"); testOk(!epicsParseUInt8("0xff", &u8, 0, NULL) && u8 == 0xff, "UInt8 '0xff'"); + testOk(!epicsParseUInt8("-1", &u8, 0, NULL) && u8 == 0xff, + "UInt8 '-1'"); testOk(epicsParseInt8("0x80", &i8, 0, NULL) == S_stdlib_overflow, "Int8 '0x80' => overflow"); testOk(epicsParseInt8("-0x81", &i8, 0, NULL) == S_stdlib_overflow, "Int8 '-0x81' => overflow"); testOk(epicsParseUInt8("0x100", &u8, 0, NULL) == S_stdlib_overflow, "UInt8 '0x100' => overflow"); + testOk(epicsParseUInt8("-0x100", &u8, 0, NULL) == S_stdlib_overflow, + "UInt8 '-0x100' => overflow"); testOk(!epicsParseInt16("0x7fff", &i16, 0, NULL) && i16 == 0x7fff, "Int16 '0x7fff'"); @@ -226,12 +236,16 @@ MAIN(epicsStdlibTest) "Int16 '-0x8000'"); testOk(!epicsParseUInt16("0xffff", &u16, 0, NULL) && u16 == 0xffff, "UInt16 '0xffff'"); + testOk(!epicsParseUInt16("-1", &u16, 0, NULL) && u16 == 0xffff, + "UInt16 '-1'"); testOk(epicsParseInt16("0x8000", &i16, 0, NULL) == S_stdlib_overflow, "Int16 '0x8000' => overflow"); testOk(epicsParseInt16("-0x8001", &i16, 0, NULL) == S_stdlib_overflow, "Int16 '-0x8001' => overflow"); testOk(epicsParseUInt16("0x10000", &u16, 0, NULL) == S_stdlib_overflow, "UInt16 '0x10000' => overflow"); + testOk(epicsParseUInt16("-0x10000", &u16, 0, NULL) == S_stdlib_overflow, + "UInt16 '-0x10000' => overflow"); testOk(!epicsParseInt32("0x7fffffff", &i32, 0, NULL) && i32 == 0x7fffffff, "Int32 '0x7fffffff'"); @@ -239,12 +253,16 @@ MAIN(epicsStdlibTest) "Int32 '-0x80000000'"); testOk(!epicsParseUInt32("0xffffffff", &u32, 0, NULL) && u32 == 0xffffffff, "UInt32 '0xffffffff'"); + testOk(!epicsParseUInt32("-1", &u32, 0, NULL) && u32 == 0xffffffffU, + "UInt32 '-1'"); testOk(epicsParseInt32("0x80000000", &i32, 0, NULL) == S_stdlib_overflow, "Int32 '0x80000000' => overflow"); testOk(epicsParseInt32("-0x80000001", &i32, 0, NULL) == S_stdlib_overflow, "Int32 '-0x80000001' => overflow"); testOk(epicsParseUInt32("0x100000000", &u32, 0, NULL) == S_stdlib_overflow, "UInt32 '0x100000000' => overflow"); + testOk(epicsParseUInt32("-0x100000000", &u32, 0, NULL) == S_stdlib_overflow, + "UInt32 '-0x100000000' => overflow"); testOk(epicsScanFloat(".1", &f) && fabs(f - 0.1) < 1e-7, "Float '.1'"); @@ -288,7 +306,7 @@ MAIN(epicsStdlibTest) testOk(epicsScanFloat("1e30", &f) && fabs(f - 1e30) < 1e24, "Float '1e30'"); - testOk(epicsScanDouble("1e300", &d) && d == 1e300, + testOk(epicsScanDouble("1e300", &d) && fabs(d - 1e300) < 1e285, "Double '1e300'"); testOk(epicsParseFloat("1e40", &f, NULL) == S_stdlib_overflow,