Skip to content

Commit

Permalink
fixed #13488 - provide error location of MathLib::to*()
Browse files Browse the repository at this point in the history
  • Loading branch information
firewave committed Jan 2, 2025
1 parent 9d34327 commit 9430f58
Show file tree
Hide file tree
Showing 18 changed files with 163 additions and 81 deletions.
28 changes: 14 additions & 14 deletions lib/checkcondition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, ";");

Expand All @@ -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));
}
}

Expand Down Expand Up @@ -170,15 +170,15 @@ 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);
}
if (Token::Match(tok2, "%varid% =", varid)) {
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);
}
Expand Down Expand Up @@ -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 == "!=";
Expand Down Expand Up @@ -267,11 +267,11 @@ void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bi
static void getnumchildren(const Token *tok, std::list<MathLib::bigint> &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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<MathLib::bigint>::max()==i1) || (std::numeric_limits<MathLib::bigint>::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;
Expand Down
2 changes: 1 addition & 1 deletion lib/checkfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/checkleakautovar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/checkstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "]|)|>"))
Expand Down
4 changes: 2 additions & 2 deletions lib/checkuninitvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,9 @@ static void conditionAlwaysTrueOrFalse(const Token *tok, const std::map<nonneg i
return;

if (tok->str() == "==")
*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);
Expand Down
14 changes: 7 additions & 7 deletions lib/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
62 changes: 39 additions & 23 deletions lib/mathlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "mathlib.h"
#include "errortypes.h"
#include "token.h"
#include "utils.h"

#include <cctype>
Expand Down Expand Up @@ -285,18 +286,23 @@ 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)) {
try {
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);
}
}

Expand All @@ -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);
}
}

Expand All @@ -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<biguint>::max())
return std::numeric_limits<biguint>::max();
// cast to bigint to avoid UBSAN warning about negative double being out-of-range
Expand All @@ -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);
}
}

Expand All @@ -364,18 +370,23 @@ 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)) {
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::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);
}
}

Expand All @@ -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);
}
}

Expand All @@ -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<bigint>::max())
return std::numeric_limits<bigint>::max();
if (doubleval < (double)std::numeric_limits<bigint>::min())
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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<double>(toBigNumber(str));
return static_cast<double>(toBigNumber(str, tok));
#ifdef _LIBCPP_VERSION
if (isFloat(str)) // Workaround libc++ bug at https://github.com/llvm/llvm-project/issues/18156
// TODO: handle locale
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit 9430f58

Please sign in to comment.