diff --git a/Makefile b/Makefile index cd134ca9a..a8c697dac 100644 --- a/Makefile +++ b/Makefile @@ -436,7 +436,7 @@ $(libcppdir)/checkboost.o: lib/checkboost.cpp lib/check.h lib/checkboost.h lib/c $(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkbufferoverrun.o $(libcppdir)/checkbufferoverrun.cpp -$(libcppdir)/checkclass.o: lib/checkclass.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h +$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkclass.o $(libcppdir)/checkclass.cpp $(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/astutils.h lib/check.h lib/checkcondition.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h @@ -478,7 +478,7 @@ $(libcppdir)/checkstl.o: lib/checkstl.cpp lib/astutils.h lib/check.h lib/checknu $(libcppdir)/checkstring.o: lib/checkstring.cpp lib/astutils.h lib/check.h lib/checkstring.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkstring.o $(libcppdir)/checkstring.cpp -$(libcppdir)/checktype.o: lib/checktype.cpp lib/check.h lib/checktype.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h +$(libcppdir)/checktype.o: lib/checktype.cpp lib/astutils.h lib/check.h lib/checktype.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checktype.o $(libcppdir)/checktype.cpp $(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/astutils.h lib/check.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h @@ -547,7 +547,7 @@ $(libcppdir)/reverseanalyzer.o: lib/reverseanalyzer.cpp lib/analyzer.h lib/astut $(libcppdir)/settings.o: lib/settings.cpp lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/timer.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/settings.o $(libcppdir)/settings.cpp -$(libcppdir)/summaries.o: lib/summaries.cpp lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/utils.h lib/valueflow.h +$(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/summaries.o $(libcppdir)/summaries.cpp $(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/path.h lib/suppressions.h lib/utils.h @@ -565,7 +565,7 @@ $(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h $(libcppdir)/token.o: lib/token.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/token.o $(libcppdir)/token.cpp -$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h +$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/check.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/tokenize.o $(libcppdir)/tokenize.cpp $(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h @@ -625,7 +625,7 @@ test/testcharvar.o: test/testcharvar.cpp lib/check.h lib/checkother.h lib/config test/testclangimport.o: test/testclangimport.cpp lib/clangimport.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclangimport.o test/testclangimport.cpp -test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkclass.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h +test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkclass.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclass.o test/testclass.cpp test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/redirect.h test/testsuite.h diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index ac44441a8..f2a0518da 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(_MSC_VER) && _MSC_VER <= 1700 // VS2012 doesn't have std::isinf and std::isnan #define ISINF(x) (!_finite(x)) @@ -294,14 +295,22 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str) { // hexadecimal numbers: if (isIntHex(str)) { - const biguint ret = std::stoull(str, nullptr, 16); - return ret; + try { + const biguint ret = std::stoull(str, nullptr, 16); + return ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); + } } // octal numbers: if (isOct(str)) { - const biguint ret = std::stoull(str, nullptr, 8); - return ret; + try { + const biguint ret = std::stoull(str, nullptr, 8); + return ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); + } } // binary numbers: @@ -329,8 +338,12 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str) return static_cast(doubleval); } - const biguint ret = std::stoull(str, nullptr, 10); - return ret; + try { + const biguint ret = std::stoull(str, nullptr, 10); + return ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); + } } unsigned int MathLib::encodeMultiChar(const std::string& str) @@ -474,19 +487,22 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str) { // hexadecimal numbers: if (isIntHex(str)) { - if (str[0] == '-') { - const bigint ret = std::stoll(str, nullptr, 16); - return ret; - } else { + try { const biguint ret = std::stoull(str, nullptr, 16); return (bigint)ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); } } // octal numbers: if (isOct(str)) { - const bigint ret = std::stoll(str, nullptr, 8); - return ret; + try { + const biguint ret = std::stoull(str, nullptr, 8); + return ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); + } } // binary numbers: @@ -520,13 +536,12 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str) return characterLiteralToLongNumber(getCharLiteral(str)); } - if (str[0] == '-') { - const bigint ret = std::stoll(str, nullptr, 10); + try { + const biguint ret = std::stoull(str, nullptr, 10); return ret; + } catch (const std::out_of_range& e) { + throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); } - - const biguint ret = std::stoull(str, nullptr, 10); - return ret; } // in-place conversion of (sub)string to double. Requires no heap. diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 7aafc3cac..ce711d518 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -20,6 +20,8 @@ #include "mathlib.h" #include "testsuite.h" +#include + struct InternalError; @@ -370,6 +372,103 @@ private: */ ASSERT_EQUALS(0x0A00000000000000LL, MathLib::toLongNumber("0x0A00000000000000LL")); + + // min/max numeric limits + ASSERT_EQUALS(std::numeric_limits::min(), MathLib::toLongNumber(std::to_string(std::numeric_limits::min()))); + ASSERT_EQUALS(std::numeric_limits::max(), MathLib::toLongNumber(std::to_string(std::numeric_limits::max()))); + ASSERT_EQUALS(std::numeric_limits::min(), MathLib::toLongNumber(std::to_string(std::numeric_limits::min()))); + ASSERT_EQUALS(std::numeric_limits::max(), MathLib::toLongNumber(std::to_string(std::numeric_limits::max()))); + + ASSERT_EQUALS(std::numeric_limits::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits::min()))); + ASSERT_EQUALS(std::numeric_limits::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits::max()))); + ASSERT_EQUALS(std::numeric_limits::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits::min()))); + ASSERT_EQUALS(std::numeric_limits::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits::max()))); + + // min/max and out-of-bounds - hex + { + const MathLib::bigint i = 0xFFFFFFFFFFFFFFFF; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("0xFFFFFFFFFFFFFFFF")); + } + { + const MathLib::biguint u = 0xFFFFFFFFFFFFFFFF; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("0xFFFFFFFFFFFFFFFF")); + } + { + const MathLib::bigint i = -0xFFFFFFFFFFFFFFFF; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("-0xFFFFFFFFFFFFFFFF")); + } + { + const MathLib::biguint u = -0xFFFFFFFFFFFFFFFF; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("-0xFFFFFFFFFFFFFFFF")); + } + + ASSERT_THROW(MathLib::toLongNumber("0x10000000000000000"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("0x10000000000000000"), InternalError); + ASSERT_THROW(MathLib::toLongNumber("-0x10000000000000000"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("-0x10000000000000000"), InternalError); + + // min/max and out-of-bounds - octal + { + const MathLib::bigint i = 01777777777777777777777; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("01777777777777777777777")); + } + { + const MathLib::biguint u = 01777777777777777777777; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("01777777777777777777777")); + } + { + const MathLib::bigint i = -01777777777777777777777; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("-01777777777777777777777")); + } + { + const MathLib::biguint u = -01777777777777777777777; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("-01777777777777777777777")); + } + + ASSERT_THROW(MathLib::toLongNumber("02000000000000000000000"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("02000000000000000000000"), InternalError); + ASSERT_THROW(MathLib::toLongNumber("-02000000000000000000000"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("-02000000000000000000000"), InternalError); + + // min/max and out-of-bounds - decimal + { + const MathLib::bigint i = 18446744073709551615; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("18446744073709551615")); + } + { + const MathLib::biguint u = 18446744073709551615; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("18446744073709551615")); + } + { + const MathLib::bigint i = -18446744073709551615; + ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); + ASSERT_EQUALS(i, MathLib::toLongNumber("-18446744073709551615")); + } + { + const MathLib::biguint u = -18446744073709551615; + ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); + ASSERT_EQUALS(u, MathLib::toULongNumber("-18446744073709551615")); + } + + ASSERT_THROW(MathLib::toLongNumber("18446744073709551616"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("18446744073709551616"), InternalError); + ASSERT_THROW(MathLib::toLongNumber("-18446744073709551616"), InternalError); + ASSERT_THROW(MathLib::toULongNumber("-18446744073709551616"), InternalError); + + // TODO: test binary + // TODO: test floating point + + // TODO: test with 128-bit values } void toDoubleNumber() const {