fix(strToInt): overflows #3580

This commit is contained in:
Alex Fabijanic
2022-06-22 23:13:39 +02:00
parent 6a97657df8
commit 284a141432
3 changed files with 281 additions and 208 deletions

View File

@@ -33,8 +33,6 @@
#if !defined(POCO_NO_LOCALE)
#include <locale>
#endif
#include <iostream>
#include <iomanip>
#if defined(POCO_NOINTMAX)
typedef Poco::UInt64 uintmax_t;
typedef Poco::Int64 intmax_t;
@@ -113,6 +111,46 @@ inline bool isIntOverflow(From val)
}
template<typename R, typename F, typename S>
bool safeMultiply(R& result, F f, S s)
{
if ((f == 0) || (s==0))
{
result = 0;
return true;
}
if (f > 0)
{
if (s > 0)
{
if (f > (std::numeric_limits<R>::max() / s))
return false;
}
else
{
if (s < (std::numeric_limits<R>::min() / f))
return false;
}
}
else
{
if (s > 0)
{
if (f < (std::numeric_limits<R>::min() / s))
return false;
}
else
{
if (s < (std::numeric_limits<R>::max() / f))
return false;
}
}
result = f * s;
return true;
}
template <typename F, typename T>
inline T& isSafeIntCast(F from)
/// Returns true if it is safe to cast
@@ -125,7 +163,7 @@ inline T& isSafeIntCast(F from)
template <typename F, typename T>
inline T& safeIntCast(F from, T& to)
/// Returns csted value if it is safe
/// Returns cast value if it is safe
/// to cast integer from F to T,
/// otherwise throws BadCastException.
{
@@ -191,49 +229,34 @@ bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
// numbers are parsed as unsigned, for negative numbers the sign is applied after parsing
// overflow is checked in every parse step
uintmax_t limitCheck = negative ? -std::numeric_limits<I>::min() : std::numeric_limits<I>::max();
I result = 0;
uintmax_t limitCheck = std::numeric_limits<I>::max();
if (negative) ++limitCheck;
uintmax_t result = 0;
unsigned char add = 0;
for (; *pStr != '\0'; ++pStr)
{
if (result > (limitCheck / base)) return false;
if (!safeMultiply(result, result, base)) return false;
switch (*pStr)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
{
unsigned char add = (*pStr - '0');
if ((limitCheck - result) < add) return false;
result = result * base + add;
}
add = (*pStr - '0');
break;
case '8': case '9':
if ((base == 10) || (base == 0x10))
{
unsigned char add = (*pStr - '0');
if ((limitCheck - result) < add) return false;
result = result * base + add;
}
if ((base == 10) || (base == 0x10)) add = (*pStr - '0');
else return false;
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
{
if (base != 0x10) return false;
unsigned char add = (*pStr - 'a');
if ((limitCheck - result) < add) return false;
result = result * base + (10 + add);
}
add = (*pStr - 'a') + 10;
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
{
if (base != 0x10) return false;
unsigned char add = (*pStr - 'A');
if ((limitCheck - result) < add) return false;
result = result * base + (10 + add);
}
add = (*pStr - 'A') + 10;
break;
case '.':
@@ -250,6 +273,8 @@ bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
default:
return false;
}
if ((limitCheck - static_cast<uintmax_t>(result)) < add) return false;
result += add;
}
if (negative && (base == 10))

View File

@@ -70,6 +70,7 @@ using Poco::MemoryInputStream;
using Poco::Stopwatch;
using Poco::RangeException;
using Poco::isIntOverflow;
using Poco::safeMultiply;
using Poco::isSafeIntCast;
using Poco::safeIntCast;
using Poco::FPEnvironment;
@@ -915,121 +916,6 @@ void StringTest::testNumericLocale()
}
void StringTest::benchmarkStrToInt()
{
Poco::Stopwatch sw;
std::string num = "123456789";
int res;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res);
sw.stop();
std::cout << "parseStream Number: " << res << std::endl;
double timeStream = sw.elapsed() / 1000.0;
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res = std::strtol(num.c_str(), &pC, 10);
sw.stop();
std::cout << "std::strtol Number: " << res << std::endl;
double timeStrtol = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
sw.stop();
std::cout << "strToInt Number: " << res << std::endl;
double timeStrToInt = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res);
sw.stop();
std::cout << "sscanf Number: " << res << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl;
}
void StringTest::benchmarkStrToFloat()
{
Poco::Stopwatch sw;
std::string num = "1.0372157551632929e-112";
std::cout << "The Number: " << num << std::endl;
double res;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res);
sw.stop();
std::cout << "parseStream Number: " << std::setprecision(std::numeric_limits<double>::digits10) << res << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard strtod
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res = std::strtod(num.c_str(), &pC);
sw.stop();
std::cout << "std::strtod Number: " << res << std::endl;
double timeStdStrtod = sw.elapsed() / 1000.0;
// POCO Way
sw.restart();
char ou = 0;
for (int i = 0; i < 1000000; ++i) strToDouble(num, res, ou);
sw.stop();
std::cout << "strToDouble Number: " << res << std::endl;
double timeStrToDouble = sw.elapsed() / 1000.0;
// standard sscanf
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res);
sw.stop();
std::cout << "sscanf Number: " << res << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
// double-conversion Strtod
sw.restart();
for (int i = 0; i < 1000000; ++i) strToDouble(num.c_str());
sw.stop();
std::cout << "Strtod Number: " << res << std::endl;
double timeStrtod = sw.elapsed() / 1000.0;
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
graph = (int) (timeStream / timeStdStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeStrToDouble << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "StrtoD:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtod) << '\t' ;
graph = (int) (timeStream / timeStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::testIntToString()
{
//intToStr(T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
@@ -1325,6 +1211,15 @@ void StringTest::testNumericStringLimit()
numericStringLowerLimit<int16_t, int8_t>();
numericStringLowerLimit<int32_t, int16_t>();
numericStringLowerLimit<int64_t, int32_t>();
multiplyOverflow<int8_t>();
multiplyOverflow<uint8_t>();
multiplyOverflow<int16_t>();
multiplyOverflow<uint16_t>();
multiplyOverflow<int32_t>();
multiplyOverflow<uint32_t>();
multiplyOverflow<int64_t>();
multiplyOverflow<uint64_t>();
}
@@ -1348,63 +1243,6 @@ void formatSprintf(double value, std::string& str)
}
void StringTest::benchmarkFloatToStr()
{
Poco::Stopwatch sw;
double val = 1.0372157551632929e-112;
std::cout << "The Number: " << std::setprecision(std::numeric_limits<double>::digits10) << val << std::endl;
std::string str;
sw.start();
for (int i = 0; i < 1000000; ++i) formatStream(val, str);
sw.stop();
std::cout << "formatStream Number: " << str << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard sprintf
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) formatSprintf(val, str);
sw.stop();
std::cout << "std::sprintf Number: " << str << std::endl;
double timeSprintf = sw.elapsed() / 1000.0;
// POCO Way (via double-conversion)
// no padding
sw.restart();
char buffer[POCO_MAX_FLT_STRING_LEN];
for (int i = 0; i < 1000000; ++i) doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, val);
sw.stop();
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
// with padding
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
sw.stop();
std::cout << "doubleToStr(std::string) Number: " << str << std::endl;
double timeDoubleToStrString = sw.elapsed() / 1000.0;
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
graph = (int) (timeStream / timeSprintf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "doubleToChar:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrChar << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrChar); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "doubleToString:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrString << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::testJSONString()
{
assertTrue (toJSON("\\", false) == "\\\\");
@@ -1471,6 +1309,201 @@ void StringTest::testJSONString()
}
void StringTest::conversionBenchmarks()
{
std::cout << std::endl << "===================" << std::endl;
benchmarkFloatToStr();
std::cout << "===================" << std::endl << std::endl;
std::cout << "===================" << std::endl;
benchmarkStrToFloat();
std::cout << "===================" << std::endl << std::endl;
std::cout << "===================" << std::endl;
benchmarkStrToInt();
std::cout << "===================" << std::endl << std::endl;
}
void StringTest::benchmarkFloatToStr()
{
Poco::Stopwatch sw;
double val = 1.0372157551632929e-112;
std::cout << "The Number: " << std::setprecision(std::numeric_limits<double>::digits10) << val << std::endl;
std::string str;
sw.start();
for (int i = 0; i < 1000000; ++i) formatStream(val, str);
sw.stop();
std::cout << "formatStream Number: " << str << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard sprintf
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) formatSprintf(val, str);
sw.stop();
std::cout << "std::sprintf Number: " << str << std::endl;
double timeSprintf = sw.elapsed() / 1000.0;
// POCO Way (via double-conversion)
// no padding
sw.restart();
char buffer[POCO_MAX_FLT_STRING_LEN];
for (int i = 0; i < 1000000; ++i) doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, val);
sw.stop();
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
// with padding
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
sw.stop();
std::cout << "doubleToStr(std::string) Number: " << str << std::endl;
double timeDoubleToStrString = sw.elapsed() / 1000.0;
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
graph = (int) (timeStream / timeSprintf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "doubleToChar:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrChar << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrChar); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "doubleToString:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrString << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::benchmarkStrToInt()
{
Poco::Stopwatch sw;
std::string num = "123456789";
int res[4] = {};
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res[0]);
sw.stop();
std::cout << "parseStream Number: " << res[0] << std::endl;
double timeStream = sw.elapsed() / 1000.0;
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[1] = std::strtol(num.c_str(), &pC, 10);
sw.stop();
std::cout << "std::strtol Number: " << res[1] << std::endl;
double timeStrtol = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res[2], 10);
sw.stop();
std::cout << "strToInt Number: " << res[2] << std::endl;
double timeStrToInt = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res[3]);
sw.stop();
std::cout << "sscanf Number: " << res[3] << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
assertEqual (res[0], res[1]);
assertEqual (res[1], res[2]);
assertEqual (res[2], res[3]);
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl;
}
void StringTest::benchmarkStrToFloat()
{
double res[5] = {};
Poco::Stopwatch sw;
std::string num = "1.0372157551632929e-112";
std::cout << "The Number: " << num << std::endl;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res[0]);
sw.stop();
std::cout << "parseStream Number: " << std::setprecision(std::numeric_limits<double>::digits10) << res[0] << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard strtod
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[1] = std::strtod(num.c_str(), &pC);
sw.stop();
std::cout << "std::strtod Number: " << res[1] << std::endl;
double timeStdStrtod = sw.elapsed() / 1000.0;
// POCO Way
sw.restart();
char ou = 0;
for (int i = 0; i < 1000000; ++i) strToDouble(num, res[2], ou);
sw.stop();
std::cout << "Poco::strToDouble(const string&, double&) Number: " << res[2] << std::endl;
double timeStrToDouble = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[3] = strToDouble(num.c_str());
sw.stop();
std::cout << "Poco::strToDouble(const char*) Number: " << res[3] << std::endl;
double timeStrtoD = sw.elapsed() / 1000.0;
// standard sscanf
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res[4]);
sw.stop();
std::cout << "sscanf Number: " << res[4] << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
assertEqual (res[0], res[1]);
assertEqual (res[1], res[2]);
assertEqual (res[2], res[3]);
assertEqual (res[3], res[4]);
int graph;
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
std::cout << std::setw(14) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
graph = (int) (timeStream / timeStdStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeStrToDouble << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtoD) << '\t' ;
graph = (int) (timeStream / timeStrtoD); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::setUp()
{
}
@@ -1510,12 +1543,10 @@ CppUnit::Test* StringTest::suite()
CppUnit_addTest(pSuite, StringTest, testNumericStringLimit);
CppUnit_addTest(pSuite, StringTest, testStringToFloatError);
CppUnit_addTest(pSuite, StringTest, testNumericLocale);
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToFloat);
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToInt);
CppUnit_addTest(pSuite, StringTest, testIntToString);
CppUnit_addTest(pSuite, StringTest, testFloatToString);
//CppUnit_addTest(pSuite, StringTest, benchmarkFloatToStr);
CppUnit_addTest(pSuite, StringTest, testJSONString);
CppUnit_addTest(pSuite, StringTest, conversionBenchmarks);
return pSuite;
}

View File

@@ -19,6 +19,7 @@
#include "Poco/NumericString.h"
#include "Poco/MemoryStream.h"
#include "Poco/NumberFormatter.h"
#include <limits>
class StringTest: public CppUnit::TestCase
@@ -53,12 +54,14 @@ public:
void testNumericStringLimit();
void testStringToFloatError();
void testNumericLocale();
void benchmarkStrToFloat();
void benchmarkStrToInt();
void testIntToString();
void testFloatToString();
void conversionBenchmarks();
void benchmarkFloatToStr();
void benchmarkStrToFloat();
void benchmarkStrToInt();
void testJSONString();
@@ -128,7 +131,6 @@ private:
assertFalse(s == std::numeric_limits<Smaller>::min());
assertTrue(Poco::strToInt<Smaller>(val, s, 10));
assertTrue (s == std::numeric_limits<Smaller>::min());
assertTrue(s == std::numeric_limits<Smaller>::min());
--l; val = Poco::NumberFormatter::format(l);
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
--l; val = Poco::NumberFormatter::format(l);
@@ -143,6 +145,21 @@ private:
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
}
template <typename T>
void multiplyOverflow()
{
T m = static_cast<T>(10);
T t = 0;
T f = std::numeric_limits<T>::max()/m;
assertTrue (Poco::safeMultiply(t, f, m));
f += 1;
assertFalse (Poco::safeMultiply(t, f, m));
f = std::numeric_limits<T>::min()/m;
assertTrue (Poco::safeMultiply(t, f, m));
f -= 1;
assertFalse (Poco::safeMultiply(t, f, m));
}
template <typename T>
bool parseStream(const std::string& s, T& value)
{