diff --git a/Makefile b/Makefile index 6cdea17c56f..c01dc8df126 100644 --- a/Makefile +++ b/Makefile @@ -589,7 +589,7 @@ $(libcppdir)/keywords.o: lib/keywords.cpp lib/config.h lib/keywords.h lib/standa $(libcppdir)/library.o: lib/library.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/library.cpp -$(libcppdir)/mathlib.o: lib/mathlib.cpp externals/simplecpp/simplecpp.h lib/config.h lib/errortypes.h lib/mathlib.h lib/utils.h +$(libcppdir)/mathlib.o: lib/mathlib.cpp externals/simplecpp/simplecpp.h lib/config.h lib/errortypes.h lib/mathlib.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/mathlib.cpp $(libcppdir)/path.o: lib/path.cpp externals/simplecpp/simplecpp.h lib/config.h lib/path.h lib/standards.h lib/utils.h @@ -784,7 +784,7 @@ test/testleakautovar.o: test/testleakautovar.cpp externals/simplecpp/simplecpp.h test/testlibrary.o: test/testlibrary.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testlibrary.cpp -test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h +test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmathlib.cpp test/testmemleak.o: test/testmemleak.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index 45202ec1b44..4f5d3a6ff1e 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -107,7 +107,7 @@ void CheckCondition::assignIf() if (Token::Match(tok->next(), "%num% [&|]")) { bitop = tok->strAt(2).at(0); - num = MathLib::toBigNumber(tok->strAt(1)); + num = MathLib::toBigNumber(tok->tokAt(1)); } else { const Token *endToken = Token::findsimplematch(tok, ";"); @@ -117,7 +117,7 @@ void CheckCondition::assignIf() if (endToken && Token::Match(endToken->tokAt(-2), "[&|] %num% ;")) { bitop = endToken->strAt(-2).at(0); - num = MathLib::toBigNumber(endToken->strAt(-1)); + num = MathLib::toBigNumber(endToken->tokAt(-1)); } } @@ -170,7 +170,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, for (const Token *tok2 = startTok; tok2; tok2 = tok2->next()) { if ((bitop == '&') && Token::Match(tok2->tokAt(2), "%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) { - const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(4)); + const MathLib::bigint num2 = MathLib::toBigNumber(tok2->tokAt(4)); if (0 == (num & num2)) mismatchingBitAndError(assignTok, num, tok2, num2); } @@ -178,7 +178,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, return true; } if (bitop == '&' && Token::Match(tok2, "%varid% &= %num% ;", varid)) { - const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(2)); + const MathLib::bigint num2 = MathLib::toBigNumber(tok2->tokAt(2)); if (0 == (num & num2)) mismatchingBitAndError(assignTok, num, tok2, num2); } @@ -213,7 +213,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, } if (Token::Match(tok2,"&&|%oror%|( %varid% ==|!= %num% &&|%oror%|)", varid)) { const Token *vartok = tok2->next(); - const MathLib::bigint num2 = MathLib::toBigNumber(vartok->strAt(2)); + const MathLib::bigint num2 = MathLib::toBigNumber(vartok->tokAt(2)); if ((num & num2) != ((bitop=='&') ? num2 : num)) { const std::string& op(vartok->strAt(1)); const bool alwaysTrue = op == "!="; @@ -267,11 +267,11 @@ void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bi static void getnumchildren(const Token *tok, std::list &numchildren) { if (tok->astOperand1() && tok->astOperand1()->isNumber()) - numchildren.push_back(MathLib::toBigNumber(tok->astOperand1()->str())); + numchildren.push_back(MathLib::toBigNumber(tok->astOperand1())); else if (tok->astOperand1() && tok->str() == tok->astOperand1()->str()) getnumchildren(tok->astOperand1(), numchildren); if (tok->astOperand2() && tok->astOperand2()->isNumber()) - numchildren.push_back(MathLib::toBigNumber(tok->astOperand2()->str())); + numchildren.push_back(MathLib::toBigNumber(tok->astOperand2())); else if (tok->astOperand2() && tok->str() == tok->astOperand2()->str()) getnumchildren(tok->astOperand2(), numchildren); } @@ -464,8 +464,8 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * if (!isSameExpression(true, expr1, expr2, *mSettings, pure, false)) return false; - const MathLib::bigint value1 = MathLib::toBigNumber(num1->str()); - const MathLib::bigint value2 = MathLib::toBigNumber(num2->str()); + const MathLib::bigint value1 = MathLib::toBigNumber(num1); + const MathLib::bigint value2 = MathLib::toBigNumber(num2); if (cond2->str() == "&") return ((value1 & value2) == value2); return ((value1 & value2) > 0); @@ -1267,14 +1267,14 @@ void CheckCondition::checkIncorrectLogicOperator() if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!=")) continue; - + // the expr are not the token of the value but they provide better context const double d1 = (isfloat) ? MathLib::toDoubleNumber(value1) : 0; const double d2 = (isfloat) ? MathLib::toDoubleNumber(value2) : 0; - const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toBigNumber(value1); - const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toBigNumber(value2); + const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toBigNumber(value1, expr1); + const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toBigNumber(value2, expr2); const bool useUnsignedInt = (std::numeric_limits::max()==i1) || (std::numeric_limits::max()==i2); - const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toBigUNumber(value1) : 0; - const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toBigUNumber(value2) : 0; + const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toBigUNumber(value1, expr1) : 0; + const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toBigUNumber(value2, expr2) : 0; // evaluate if expression is always true/false bool alwaysTrue = true, alwaysFalse = true; bool firstTrue = true, secondTrue = true; diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index 607d083aaa2..49abcc50595 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -582,7 +582,7 @@ void CheckFunctions::memsetInvalid2ndParam() } if (printWarning && secondParamTok->isNumber()) { // Check if the second parameter is a literal and is out of range - const MathLib::bigint value = MathLib::toBigNumber(secondParamTok->str()); + const MathLib::bigint value = MathLib::toBigNumber(secondParamTok); const long long sCharMin = mSettings->platform.signedCharMin(); const long long uCharMax = mSettings->platform.unsignedCharMax(); if (value < sCharMin || value > uCharMax) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index bdc92a8f6ed..b621b2558c0 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -474,7 +474,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, // Assigning non-zero value variable. It might be used to // track the execution for a later if condition. - if (Token::Match(varTok->tokAt(2), "%num% ;") && MathLib::toBigNumber(varTok->strAt(2)) != 0) + if (Token::Match(varTok->tokAt(2), "%num% ;") && MathLib::toBigNumber(varTok->tokAt(2)) != 0) notzero.insert(varTok->varId()); else if (Token::Match(varTok->tokAt(2), "- %type% ;") && varTok->tokAt(3)->isUpperCaseName()) notzero.insert(varTok->varId()); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 73c9f03e7e2..f71ecbb7e8d 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3216,7 +3216,7 @@ void CheckOther::checkIncompleteArrayFill() if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0)) continue; - if (MathLib::toBigNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) { + if (MathLib::toBigNumber(tok->linkAt(1)->tokAt(-1)) == var->dimension(0)) { int size = mTokenizer->sizeOfType(var->typeStartToken()); if (size == 0 && var->valueType()->pointer) size = mSettings->platform.sizeof_pointer; diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp index 462f053446a..1d145f30cbb 100644 --- a/lib/checkstring.cpp +++ b/lib/checkstring.cpp @@ -294,7 +294,7 @@ void CheckString::checkIncorrectStringCompare() tok = tok->linkAt(1); if (Token::simpleMatch(tok, ". substr (") && Token::Match(tok->tokAt(3)->nextArgument(), "%num% )")) { - const MathLib::biguint clen = MathLib::toBigUNumber(tok->linkAt(2)->strAt(-1)); + const MathLib::biguint clen = MathLib::toBigUNumber(tok->linkAt(2)->tokAt(-1)); const Token* begin = tok->previous(); for (;;) { // Find start of statement while (begin->link() && Token::Match(begin, "]|)|>")) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 3fe012470bf..541a46c071f 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -332,9 +332,9 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::mapstr() == "==") - *alwaysTrue = (it->second == MathLib::toBigNumber(numtok->str())); + *alwaysTrue = (it->second == MathLib::toBigNumber(numtok)); else if (tok->str() == "!=") - *alwaysTrue = (it->second != MathLib::toBigNumber(numtok->str())); + *alwaysTrue = (it->second != MathLib::toBigNumber(numtok)); else return; *alwaysFalse = !(*alwaysTrue); diff --git a/lib/library.cpp b/lib/library.cpp index 8c7f6e335ba..6872553c791 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -1059,13 +1059,13 @@ bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint TokenList tokenList(nullptr); gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList); for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { - if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok->str())) + if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok)) return true; - if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toBigNumber(tok->str()) && argvalue <= MathLib::toBigNumber(tok->strAt(2))) + if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toBigNumber(tok) && argvalue <= MathLib::toBigNumber(tok->tokAt(2))) return true; - if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toBigNumber(tok->str())) + if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toBigNumber(tok)) return true; - if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toBigNumber(tok->strAt(1))) + if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toBigNumber(tok->tokAt(1))) return true; } return false; @@ -1079,11 +1079,11 @@ bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) con TokenList tokenList(nullptr); gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList); for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { - if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok->str()) && argvalue <= MathLib::toDoubleNumber(tok->strAt(2))) + if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok) && argvalue <= MathLib::toDoubleNumber(tok->tokAt(2))) return true; - if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok->str())) + if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok)) return true; - if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1))) + if ((!tok->previous() || tok->strAt(-1) == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->tokAt(1))) return true; if (Token::Match(tok, "%num%") && MathLib::isFloat(tok->str()) && MathLib::isEqual(tok->str(), MathLib::toString(argvalue))) return true; diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 75378d9006e..a818681acbc 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -19,6 +19,7 @@ #include "mathlib.h" #include "errortypes.h" +#include "token.h" #include "utils.h" #include @@ -285,8 +286,13 @@ MathLib::value MathLib::value::shiftRight(const MathLib::value &v) const return ret; } +MathLib::biguint MathLib::toBigUNumber(const Token * tok) +{ + return toBigUNumber(tok->str(), tok); +} + // TODO: remove handling of non-literal stuff -MathLib::biguint MathLib::toBigUNumber(const std::string & str) +MathLib::biguint MathLib::toBigUNumber(const std::string & str, const Token * const tok) { // hexadecimal numbers: if (isIntHex(str)) { @@ -294,9 +300,9 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str) const biguint ret = std::stoull(str, nullptr, 16); return ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); } } @@ -306,9 +312,9 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str) const biguint ret = std::stoull(str, nullptr, 8); return ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); } } @@ -331,7 +337,7 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str) // Things are going to be less precise now: the value can't be represented in the biguint type. // Use min/max values as an approximation. See #5843 // TODO: bail out when we are out of range? - const double doubleval = toDoubleNumber(str); + const double doubleval = toDoubleNumber(str, tok); if (doubleval > (double)std::numeric_limits::max()) return std::numeric_limits::max(); // cast to bigint to avoid UBSAN warning about negative double being out-of-range @@ -347,13 +353,13 @@ MathLib::biguint MathLib::toBigUNumber(const std::string & str) if (idx != str.size()) { const std::string s = str.substr(idx); if (!isValidIntegerSuffix(s, true)) - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: " + str); } return ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigUNumber: invalid_argument: " + str); } } @@ -364,8 +370,13 @@ unsigned int MathLib::encodeMultiChar(const std::string& str) }); } +MathLib::bigint MathLib::toBigNumber(const Token * tok) +{ + return toBigNumber(tok->str(), tok); +} + // TODO: remove handling of non-literal stuff -MathLib::bigint MathLib::toBigNumber(const std::string & str) +MathLib::bigint MathLib::toBigNumber(const std::string & str, const Token * const tok) { // hexadecimal numbers: if (isIntHex(str)) { @@ -373,9 +384,9 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str) const biguint ret = std::stoull(str, nullptr, 16); return (bigint)ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); } } @@ -385,9 +396,9 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str) const biguint ret = std::stoull(str, nullptr, 8); return ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); } } @@ -410,7 +421,7 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str) // Things are going to be less precise now: the value can't be represented in the bigint type. // Use min/max values as an approximation. See #5843 // TODO: bail out when we are out of range? - const double doubleval = toDoubleNumber(str); + const double doubleval = toDoubleNumber(str, tok); if (doubleval > (double)std::numeric_limits::max()) return std::numeric_limits::max(); if (doubleval < (double)std::numeric_limits::min()) @@ -427,13 +438,13 @@ MathLib::bigint MathLib::toBigNumber(const std::string & str) if (idx != str.size()) { const std::string s = str.substr(idx); if (!isValidIntegerSuffix(s, true)) - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: input was not completely consumed: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: input was not completely consumed: " + str); } return ret; } catch (const std::out_of_range& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: out_of_range: " + str); } catch (const std::invalid_argument& /*e*/) { - throw InternalError(nullptr, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); + throw InternalError(tok, "Internal Error. MathLib::toBigNumber: invalid_argument: " + str); } } @@ -484,17 +495,22 @@ static double floatHexToDoubleNumber(const std::string& str) return factor1 * factor2; } -double MathLib::toDoubleNumber(const std::string &str) +double MathLib::toDoubleNumber(const Token * tok) +{ + return toDoubleNumber(tok->str(), tok); +} + +double MathLib::toDoubleNumber(const std::string &str, const Token * const tok) { if (isCharLiteral(str)) { try { return simplecpp::characterLiteralToLL(str); } catch (const std::exception& e) { - throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL(" + str + ") => " + e.what()); + throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL(" + str + ") => " + e.what()); } } if (isIntHex(str)) - return static_cast(toBigNumber(str)); + return static_cast(toBigNumber(str, tok)); #ifdef _LIBCPP_VERSION if (isFloat(str)) // Workaround libc++ bug at https://github.com/llvm/llvm-project/issues/18156 // TODO: handle locale @@ -508,13 +524,13 @@ double MathLib::toDoubleNumber(const std::string &str) istr.imbue(std::locale::classic()); double ret; if (!(istr >> ret)) - throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: conversion failed: " + str); + throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: conversion failed: " + str); std::string s; if (istr >> s) { if (isDecimalFloat(str)) return ret; if (!isValidIntegerSuffix(s, true)) - throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: " + str); + throw InternalError(tok, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: " + str); } return ret; } diff --git a/lib/mathlib.h b/lib/mathlib.h index f83894c62b5..f0f1e2a7e6f 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -30,6 +30,8 @@ #include #endif +class Token; + /// @addtogroup Core /// @{ @@ -81,13 +83,19 @@ class CPPCHECKLIB MathLib { static const int bigint_bits; /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ - static bigint toBigNumber(const std::string & str); + static bigint toBigNumber(const Token * tok); + /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ + static bigint toBigNumber(const std::string & str, const Token *tok = nullptr); /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ - static biguint toBigUNumber(const std::string & str); + static biguint toBigUNumber(const Token * tok); + /** @brief for conversion of numeric literals - for atoi-like conversions please use strToInt() */ + static biguint toBigUNumber(const std::string & str, const Token *tok = nullptr); template static std::string toString(T value) = delete; /** @brief for conversion of numeric literals */ - static double toDoubleNumber(const std::string & str); + static double toDoubleNumber(const Token * tok); + /** @brief for conversion of numeric literals */ + static double toDoubleNumber(const std::string & str, const Token * tok = nullptr); static bool isInt(const std::string & str); static bool isFloat(const std::string &str); diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index f64b919f4f9..4f96c8f4be3 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -1383,7 +1383,7 @@ namespace { if (expr->isNumber()) { if (MathLib::isFloat(expr->str())) return unknown(); - MathLib::bigint i = MathLib::toBigNumber(expr->str()); + MathLib::bigint i = MathLib::toBigNumber(expr); if (i < 0 && astIsUnsigned(expr)) return unknown(); return ValueFlow::Value{i}; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 76cf60eadaf..6c3aa0b2ea1 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1831,7 +1831,7 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow() if (Token::Match(tokenList.front(), "; %num% ;")) { dimension.known = true; - dimension.num = MathLib::toBigNumber(tokenList.front()->strAt(1)); + dimension.num = MathLib::toBigNumber(tokenList.front()->tokAt(1)); } continue; @@ -3698,7 +3698,7 @@ bool Variable::arrayDimensions(const Settings& settings, bool& isContainer) if (Token::Match(tok, "%num% [,>]")) { dimension_.tok = tok; dimension_.known = true; - dimension_.num = MathLib::toBigNumber(tok->str()); + dimension_.num = MathLib::toBigNumber(tok); } else if (tok) { dimension_.tok = tok; dimension_.known = false; @@ -7441,7 +7441,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to const bool unsignedSuffix = (tokStr.find_last_of("uU") != std::string::npos); ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED; ValueType::Type type = ValueType::Type::INT; - const MathLib::biguint value = MathLib::toBigUNumber(tokStr); + const MathLib::biguint value = MathLib::toBigUNumber(tokStr, tok); for (std::size_t pos = tokStr.size() - 1U; pos > 0U; --pos) { const char suffix = tokStr[pos]; if (suffix == 'u' || suffix == 'U') diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index b81ff82da9d..f72f48914fe 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -2516,9 +2516,9 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end, st MathLib::isInt(tok->strAt(2))) { if ((Token::Match(tok->previous(), "(|&&|%oror%|,") || tok == start) && (Token::Match(tok->tokAt(3), ")|&&|%oror%|?") || tok->tokAt(3) == end)) { - const MathLib::bigint op1(MathLib::toBigNumber(tok->str())); + const MathLib::bigint op1(MathLib::toBigNumber(tok)); const std::string &cmp(tok->strAt(1)); - const MathLib::bigint op2(MathLib::toBigNumber(tok->strAt(2))); + const MathLib::bigint op2(MathLib::toBigNumber(tok->tokAt(2))); std::string result; @@ -2689,7 +2689,7 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, const Token *ba if (validTokenEnd(bounded, tok, backToken, 3) && Token::Match(tok->previous(), "(|&&|%oror% %char% %comp% %num% &&|%oror%|)")) { - tok->str(MathLib::toString(MathLib::toBigNumber(tok->str()))); + tok->str(MathLib::toString(MathLib::toBigNumber(tok))); } if (validTokenEnd(bounded, tok, backToken, 5) && @@ -2885,9 +2885,9 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, const Token *ba if (validTokenStart(bounded, tok, frontToken, -1) && Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%|?")) { - const MathLib::bigint op1(MathLib::toBigNumber(tok->str())); + const MathLib::bigint op1(MathLib::toBigNumber(tok)); const std::string &cmp(tok->strAt(1)); - const MathLib::bigint op2(MathLib::toBigNumber(tok->strAt(2))); + const MathLib::bigint op2(MathLib::toBigNumber(tok->tokAt(2))); std::string result; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 907c7c48ac3..ea4fde04355 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3839,7 +3839,7 @@ void Tokenizer::arraySize() if (tok2->link() && Token::Match(tok2, "{|(|[|<")) { if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer if (Token::Match(tok2, "[ %num% ]")) - sz = std::max(sz, MathLib::toBigUNumber(tok2->strAt(1)) + 1U); + sz = std::max(sz, MathLib::toBigUNumber(tok2->tokAt(1)) + 1U); else { sz = 0; break; @@ -4019,8 +4019,8 @@ void Tokenizer::simplifyCaseRange() { for (Token* tok = list.front(); tok; tok = tok->next()) { if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) { - const MathLib::bigint start = MathLib::toBigNumber(tok->strAt(1)); - MathLib::bigint end = MathLib::toBigNumber(tok->strAt(3)); + const MathLib::bigint start = MathLib::toBigNumber(tok->tokAt(1)); + MathLib::bigint end = MathLib::toBigNumber(tok->tokAt(3)); end = std::min(start + 50, end); // Simplify it 50 times at maximum if (start < end) { tok = tok->tokAt(2); @@ -9353,10 +9353,10 @@ void Tokenizer::simplifyCppcheckAttribute() if (vartok->isName()) { if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )")) vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, - MathLib::toBigNumber(tok->strAt(1))); + MathLib::toBigNumber(tok->tokAt(1))); else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )")) vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, - MathLib::toBigNumber(tok->strAt(1))); + MathLib::toBigNumber(tok->tokAt(1))); } // Delete cppcheck attribute.. @@ -9428,16 +9428,16 @@ void Tokenizer::simplifyCPPAttribute() if (argtok && argtok->str() == vartok->str()) { if (vartok->strAt(1) == ">=") argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, - MathLib::toBigNumber(vartok->strAt(2))); + MathLib::toBigNumber(vartok->tokAt(2))); else if (vartok->strAt(1) == ">") argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, - MathLib::toBigNumber(vartok->strAt(2)) + 1); + MathLib::toBigNumber(vartok->tokAt(2)) + 1); else if (vartok->strAt(1) == "<=") argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, - MathLib::toBigNumber(vartok->strAt(2))); + MathLib::toBigNumber(vartok->tokAt(2))); else if (vartok->strAt(1) == "<") argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, - MathLib::toBigNumber(vartok->strAt(2)) - 1); + MathLib::toBigNumber(vartok->tokAt(2)) - 1); } } } else { @@ -9894,7 +9894,7 @@ void Tokenizer::simplifyBitfields() !Token::simpleMatch(tok->tokAt(2), "default :")) { Token *tok1 = (tok->strAt(1) == "const") ? tok->tokAt(3) : tok->tokAt(2); if (Token::Match(tok1, "%name% : %num% [;=]")) - tok1->setBits(static_cast(MathLib::toBigNumber(tok1->strAt(2)))); + tok1->setBits(static_cast(MathLib::toBigNumber(tok1->tokAt(2)))); if (tok1 && tok1->tokAt(2) && (Token::Match(tok1->tokAt(2), "%bool%|%num%") || !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) { diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 88035c2d162..69ce0b280c5 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -824,9 +824,9 @@ static void valueFlowBitAnd(TokenList& tokenlist, const Settings& settings) MathLib::bigint number; if (MathLib::isInt(tok->astOperand1()->str())) - number = MathLib::toBigNumber(tok->astOperand1()->str()); + number = MathLib::toBigNumber(tok->astOperand1()); else if (MathLib::isInt(tok->astOperand2()->str())) - number = MathLib::toBigNumber(tok->astOperand2()->str()); + number = MathLib::toBigNumber(tok->astOperand2()); else continue; @@ -5467,7 +5467,7 @@ static void valueFlowSwitchVariable(const TokenList& tokenlist, } if (Token::Match(tok, "case %num% :")) { std::list values; - values.emplace_back(MathLib::toBigNumber(tok->strAt(1))); + values.emplace_back(MathLib::toBigNumber(tok->tokAt(1))); values.back().condition = tok; values.back().errorPath.emplace_back(tok, "case " + tok->strAt(1) + ": " + vartok->str() + " is " + @@ -5481,7 +5481,7 @@ static void valueFlowSwitchVariable(const TokenList& tokenlist, tok = tok->tokAt(3); if (!tok->isName()) tok = tok->next(); - values.emplace_back(MathLib::toBigNumber(tok->strAt(1))); + values.emplace_back(MathLib::toBigNumber(tok->tokAt(1))); values.back().condition = tok; values.back().errorPath.emplace_back(tok, "case " + tok->strAt(1) + ": " + vartok->str() + " is " + diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 306f90d8db9..0717cb6db66 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -120,7 +120,7 @@ namespace ValueFlow { if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) { try { - MathLib::bigint signedValue = MathLib::toBigNumber(tok->str()); + MathLib::bigint signedValue = MathLib::toBigNumber(tok); const ValueType* vt = tok->valueType(); if (vt && vt->sign == ValueType::UNSIGNED && signedValue < 0 && getSizeOf(*vt, settings) < sizeof(MathLib::bigint)) { MathLib::bigint minValue{}, maxValue{}; @@ -137,7 +137,7 @@ namespace ValueFlow } else if (tok->isNumber() && MathLib::isFloat(tok->str())) { Value value; value.valueType = Value::ValueType::FLOAT; - value.floatValue = MathLib::toDoubleNumber(tok->str()); + value.floatValue = MathLib::toDoubleNumber(tok); if (!tok->isTemplateArg()) value.setKnown(); setTokenValue(tok, std::move(value), settings); @@ -291,7 +291,7 @@ namespace ValueFlow const Token* num = brac->astOperand2(); if (num && ((num->isNumber() && MathLib::isInt(num->str())) || num->tokType() == Token::eChar)) { try { - const MathLib::biguint dim = MathLib::toBigUNumber(num->str()); + const MathLib::biguint dim = MathLib::toBigUNumber(num); sz *= dim; brac = brac->astParent(); continue; diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index db4fa5cd6c5..4203c9deb46 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -285,7 +285,7 @@ $(libcppdir)/keywords.o: ../lib/keywords.cpp ../lib/config.h ../lib/keywords.h . $(libcppdir)/library.o: ../lib/library.cpp ../externals/tinyxml2/tinyxml2.h ../lib/astutils.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/library.cpp -$(libcppdir)/mathlib.o: ../lib/mathlib.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/utils.h +$(libcppdir)/mathlib.o: ../lib/mathlib.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/errortypes.h ../lib/mathlib.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/mathlib.cpp $(libcppdir)/path.o: ../lib/path.cpp ../externals/simplecpp/simplecpp.h ../lib/config.h ../lib/path.h ../lib/standards.h ../lib/utils.h diff --git a/test/cli/other_test.py b/test/cli/other_test.py index c5668c8f4fd..720b483d458 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2719,3 +2719,26 @@ def test_xml_builddir(tmp_path): # #13391 / #13485 assert exitcode_1 == exitcode_2, stdout_2 assert stdout_1 == stdout_2 assert stderr_1 == stderr_2 + + +def test_internal_error_loc_int(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, 'wt') as f: + f.write( +""" +void f() { + int i = 0x10000000000000000; +} +""") + + args = [ + '-q', + '--template=simple', + str(test_file) + ] + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + assert stdout.splitlines() == [] + assert stderr.splitlines() == [ + '{}:3:13: error: Internal Error. MathLib::toBigUNumber: out_of_range: 0x10000000000000000 [internalError]'.format(test_file) + ] \ No newline at end of file diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 70cc9b947a4..c2494b6712b 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -17,8 +17,10 @@ */ #include "config.h" -#include "mathlib.h" #include "fixture.h" +#include "mathlib.h" +#include "token.h" +#include "tokenlist.h" #include #include @@ -405,6 +407,17 @@ class TestMathLib : public TestFixture { ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("1invalid"), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1invalid"); ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("1 invalid"), INTERNAL, "Internal Error. MathLib::toBigNumber: input was not completely consumed: 1 invalid"); + { + TokenList list{&settingsDefault}; + list.appendFileIfNew("test.c"); + TokensFrontBack tokensFrontBack(list); + auto *tok = new Token(tokensFrontBack); + tok->str("invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber(tok), INTERNAL, "Internal Error. MathLib::toBigNumber: invalid_argument: invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toBigNumber: invalid_argument: invalid"); + TokenList::deleteTokens(tok); + } + // TODO: test binary // TODO: test floating point @@ -570,6 +583,17 @@ class TestMathLib : public TestFixture { ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("1invalid"), INTERNAL, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: 1invalid"); ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("1 invalid"), INTERNAL, "Internal Error. MathLib::toBigUNumber: input was not completely consumed: 1 invalid"); + { + TokenList list{&settingsDefault}; + list.appendFileIfNew("test.c"); + TokensFrontBack tokensFrontBack(list); + auto *tok = new Token(tokensFrontBack); + tok->str("invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber(tok), INTERNAL, "Internal Error. MathLib::toBigUNumber: invalid_argument: invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toBigUNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toBigUNumber: invalid_argument: invalid"); + TokenList::deleteTokens(tok); + } + // TODO: test binary // TODO: test floating point @@ -689,6 +713,17 @@ class TestMathLib : public TestFixture { //ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("1.0ll"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.0ll"); //ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("1.0LL"), INTERNAL, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.0LL"); + { + TokenList list{&settingsDefault}; + list.appendFileIfNew("test.c"); + TokensFrontBack tokensFrontBack(list); + auto *tok = new Token(tokensFrontBack); + tok->str("invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber(tok), INTERNAL, "Internal Error. MathLib::toDoubleNumber: conversion failed: invalid"); + ASSERT_THROW_INTERNAL_EQUALS(MathLib::toDoubleNumber("invalid", tok), INTERNAL, "Internal Error. MathLib::toDoubleNumber: conversion failed: invalid"); + TokenList::deleteTokens(tok); + } + // verify: string --> double --> string conversion // TODO: add L, min/max ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0f")));