63 bool hasParent =
false;
71 if (
mCondDiags.count(tok) == 0 && !hasParent) {
82 if (
Token::Match(tok,
"= & %var% ;") && vars.find(tok->tokAt(2)->varId()) != vars.end())
96 if (tok->str() !=
"=")
100 const Variable *var = tok->previous()->variable();
108 bitop = tok->strAt(2).at(0);
118 bitop = endToken->
strAt(-2).at(0);
126 if (num < 0 && bitop ==
'|')
137 int argumentNumber = 0;
139 for (ftok = partok; ftok && ftok->
str() !=
"("; ftok = ftok->
previous()) {
140 if (ftok->
str() ==
")")
142 else if (argumentNumber == 0U && ftok->
str() ==
"&")
144 else if (ftok->
str() ==
",")
147 ftok = ftok ? ftok->
previous() :
nullptr;
162 const Token *
const startTok,
170 for (
const Token *tok2 = startTok; tok2; tok2 = tok2->
next()) {
171 if ((bitop ==
'&') &&
Token::Match(tok2->tokAt(2),
"%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) {
173 if (0 == (num & num2))
179 if (bitop ==
'&' &&
Token::Match(tok2,
"%varid% &= %num% ;", varid)) {
181 if (0 == (num & num2))
188 if (tok2->str() ==
"}")
192 if (ret && tok2->str() ==
";")
197 if (!islocal && tok2->str() ==
"while")
199 if (tok2->str() ==
"while") {
202 const Token *bodyEnd = bodyStart ? bodyStart->
link() :
nullptr;
209 for (; tok2 != end; tok2 = tok2->
next()) {
210 if (
Token::Match(tok2,
"[(,] &| %varid% [,)]", varid)) {
213 if (
Token::Match(tok2,
"&&|%oror%|( %varid% ==|!= %num% &&|%oror%|)", varid)) {
216 if ((num & num2) != ((bitop==
'&') ? num2 : num)) {
217 const std::string& op(vartok->
strAt(1));
218 const bool alwaysTrue = op ==
"!=";
219 const std::string condition(vartok->
str() + op + vartok->
strAt(2));
223 if (
Token::Match(tok2,
"%varid% %op%", varid) && tok2->next()->isAssignmentOp()) {
243 std::list<const Token *> locations = { tok1, tok2 };
253 std::list<const Token *> locations = { tok1, tok2 };
255 std::ostringstream msg;
256 msg <<
"Mismatching bitmasks. Result is always 0 ("
257 <<
"X = Y & 0x" << std::hex << num1 <<
"; Z = X & 0x" << std::hex << num2 <<
"; => Z=0).";
281 const Scope *scope = tok ? tok->
scope() :
nullptr;
282 while (scope && scope->
isLocal())
312 logChecker(
"CheckCondition::checkBadBitmaskCheck");
315 if (tok->str() ==
"|" && tok->astOperand1() && tok->astOperand2() && tok->astParent()) {
317 const bool isBoolean =
Token::Match(parent,
"&&|%oror%") ||
323 const bool isTrue = (tok->astOperand1()->hasKnownIntValue() && tok->astOperand1()->values().front().intvalue != 0) ||
324 (tok->astOperand2()->hasKnownIntValue() && tok->astOperand2()->values().front().intvalue != 0);
330 const auto& startStop = tok->findExpressionStartEndTokens();
334 const bool isZero1 = (tok->astOperand1()->hasKnownIntValue() && tok->astOperand1()->values().front().intvalue == 0);
335 const bool isZero2 = (tok->astOperand2()->hasKnownIntValue() && tok->astOperand2()->values().front().intvalue == 0);
336 if (!isZero1 && !isZero2)
339 if (!tok->isExpandedMacro() &&
363 if (!tok->isComparisonOp())
368 if (!expr1 || !expr2)
371 std::swap(expr1,expr2);
379 std::list<MathLib::bigint> numbers;
385 if ((expr1->
str() ==
"&" && (num1 & num2) != num2) ||
386 (expr1->
str() ==
"|" && (num1 | num2) != num2)) {
387 const std::string& op(tok->str());
390 }
else if (expr1->
str() ==
"&") {
392 const std::string& op(tok->str());
395 }
else if ((
Token::Match(tok,
"<=|>")) && (num1 <= num2)) {
398 }
else if (expr1->
str() ==
"|") {
400 (expr1->
astOperand1()->valueType()->sign == ValueType::Sign::UNSIGNED)) {
402 const std::string& op(tok->str());
407 }
else if ((
Token::Match(tok,
"<=|>")) && (num1 > num2)) {
420 std::ostringstream expression;
421 expression << std::hex <<
"(X " << bitop <<
" 0x" << value1 <<
") " << op <<
" 0x" << value2;
423 const std::string errmsg(
"Expression '" + expression.str() +
"' is always " +
bool_to_string(result) +
".\n"
424 "The expression '" + expression.str() +
"' is always " +
bool_to_string(result) +
425 ". Check carefully constants and operators used, these errors might be hard to "
426 "spot sometimes. In case of complex expression it might help to split it to "
427 "separate expressions.");
434 if (!cond1 || !cond2)
448 std::swap(expr1,num1);
457 std::swap(expr2,num2);
466 if (cond2->
str() ==
"&")
467 return ((value1 & value2) == value2);
468 return ((value1 & value2) > 0);
478 logChecker(
"CheckCondition::duplicateCondition");
516 errorPath.emplace_back(tok1,
"First condition");
517 errorPath.emplace_back(tok2,
"Second condition");
519 std::string msg =
"The if condition is the same as the previous if condition";
551 tok2 = tok2->
tokAt(4);
571 std::ostringstream errmsg;
572 errmsg <<
"Expression is always false because 'else if' condition matches previous condition at line "
580 if (
diag(ifCond) &
diag(elseIfCond))
582 std::ostringstream errmsg;
583 errmsg <<
"Expression is always true because 'else if' condition is opposite to previous condition at line "
584 << ifCond->
linenr() <<
".";
586 errorPath.emplace_back(ifCond,
"first condition");
587 errorPath.emplace_back(elseIfCond,
"else if condition is opposite to first condition");
603 while (obj && obj->
str() ==
".")
621 logChecker(
"CheckCondition::multiCondition2");
626 const Token *condTok =
nullptr;
631 if (!condTok || condTok->
str() !=
";")
634 if (!condTok || condTok->
str() !=
";")
640 const Token *
const cond1 = condTok;
645 bool functionCall =
false;
646 bool nonConstFunctionCall =
false;
647 bool nonlocal =
false;
650 [&](
const Token *cond) {
654 if (nonConstFunctionCall)
659 vars.insert(cond->
varId());
661 if (!nonlocal && var) {
668 }
else if (!nonlocal && cond->
isName()) {
677 if (nonConstFunctionCall)
680 std::vector<const Variable*> varsInCond;
682 [&varsInCond](
const Token *cond) {
684 const Variable *var = cond->variable();
685 if (std::find(varsInCond.cbegin(), varsInCond.cend(), var) == varsInCond.cend())
686 varsInCond.push_back(var);
692 enum MULTICONDITIONTYPE { INNER, AFTER };
696 std::vector<MULTICONDITIONTYPE> types = {MULTICONDITIONTYPE::INNER};
698 types.push_back(MULTICONDITIONTYPE::AFTER);
699 for (
const MULTICONDITIONTYPE type:types) {
700 if (type == MULTICONDITIONTYPE::AFTER) {
705 const Token *
const endToken = tok->
scope()->bodyEnd;
707 for (; tok && tok != endToken; tok = tok->
next()) {
711 const Token * condStartToken = tok->
str() ==
"if" ? tok->
next() : tok;
719 const bool isReturnVar = (tok->
str() ==
"return" && (!
Token::Match(cond2,
"%cop%") || (cond2 && cond2->
isUnaryOp(
"!"))));
723 if (type == MULTICONDITIONTYPE::INNER) {
727 if (firstCondition->
str() ==
"&&") {
728 if (!isOppositeCond(false, firstCondition, cond2, *mSettings, true, true))
729 return ChildrenToVisit::op1_and_op2;
732 if (!isReturnVar && isOppositeCond(false, firstCondition, cond2, *mSettings, true, true, &errorPath)) {
733 if (!isAliased(vars))
734 oppositeInnerConditionError(firstCondition, cond2, errorPath);
743 if (secondCondition->
str() ==
"||" || secondCondition->
str() ==
"&&")
749 identicalConditionAfterEarlyExitError(cond1, secondCondition, errorPath);
750 return ChildrenToVisit::done;
786 const bool changed = std::any_of(vars.cbegin(), vars.cend(), [&](
int varid) {
787 return isVariableChanged(tok1, tok2, varid, nonlocal, *mSettings);
792 if ((tok->
varId() && vars.find(tok->
varId()) != vars.end()) ||
793 (!tok->
varId() && nonlocal) ||
798 const Token *parent = tok;
821 if (!
function || !function->isConst())
851 errorPath.emplace_back(tok1,
"outer condition: " + s1);
852 errorPath.emplace_back(tok2,
"opposite inner condition: " + s2);
854 const std::string msg(
"Opposite inner '" + innerSmt +
"' condition leads to a dead code block.\n"
855 "Opposite inner '" + innerSmt +
"' condition leads to a dead code block (outer condition is '" + s1 +
"' and inner condition is '" + s2 +
"').");
866 errorPath.emplace_back(tok1,
"outer condition: " + s1);
867 errorPath.emplace_back(tok2,
"identical inner condition: " + s2);
869 const std::string msg(
"Identical inner '" + innerSmt +
"' condition is always true.\n"
870 "Identical inner '" + innerSmt +
"' condition is always true (outer condition is '" + s1 +
"' and inner condition is '" + s2 +
"').");
882 const std::string value = (cond2 && cond2->
valueType() && cond2->
valueType()->
type == ValueType::Type::BOOL) ?
"false" :
"0";
884 errorPath.emplace_back(cond1,
"If condition '" + cond +
"' is true, the function will return/exit");
885 errorPath.emplace_back(cond2, (isReturnValue ?
"Returning identical expression '" :
"Testing identical condition '") + cond +
"'");
889 "identicalConditionAfterEarlyExit",
891 ? (
"Identical condition and return expression '" + cond +
"', return value is always " + value)
892 : (
"Identical condition '" + cond +
"', second condition is always false"),
918 else if (s[0] ==
'>')
925 return static_cast<int>(v > 0) -
static_cast<int>(v < 0);
930 static int sufficientCondition(std::string op1,
const bool not1,
const T value1, std::string op2,
const bool not2,
const T value2,
const bool isAnd) {
931 auto transformOp = [](std::string& op,
const bool invert) {
947 transformOp(
op1, not1);
948 transformOp(
op2, not2);
953 if (
op1 ==
">" ||
op1 ==
">=")
954 res =
sign(value1 - value2);
955 else if (
op1 ==
"<" ||
op1 ==
"<=")
956 res = -
sign(value1 - value2);
960 else if (
op2 ==
"!=")
962 else if (
op1 ==
"==")
964 else if (
op2 ==
"==")
966 else if (
op1 ==
">" &&
op2 ==
">=")
967 res =
sign(value1 - (value2 - 1));
968 else if (
op1 ==
">=" &&
op2 ==
">")
969 res =
sign((value1 - 1) - value2);
970 else if (
op1 ==
"<" &&
op2 ==
"<=")
971 res = -
sign(value1 - (value2 + 1));
972 else if (
op1 ==
"<=" &&
op2 ==
"<")
973 res = -
sign((value1 + 1) - value2);
975 return res * (isAnd == equal ? 1 : -1);
981 return (op ==
"==" && value1 == value2) ||
982 (op ==
"!=" && value1 != value2) ||
983 (op ==
">" && value1 > value2) ||
984 (op ==
">=" && value1 >= value2) ||
985 (op ==
"<" && value1 < value2) ||
986 (op ==
"<=" && value1 <= value2);
991 return (op ==
">" && value1 > value2) ||
992 (op ==
">=" && value1 >= value2) ||
993 (op ==
"<" && value1 < value2) ||
994 (op ==
"<=" && value1 <= value2);
1000 const T min = std::min(value1, value2);
1001 if (min== std::numeric_limits<T>::max())
1009 return (value1 + value2) / 2.0;
1014 static inline T
getvalue(
const int test,
const T value1,
const T value2)
1024 return std::numeric_limits<T>::lowest();
1028 return getvalue3<T>(value1, value2);
1032 return std::numeric_limits<T>::max();
1040 while (comp && comp->
str() ==
"!") {
1054 }
else if (
op1->isLiteral()) {
1055 if (
op1->isExpandedMacro())
1058 if (
op1->enumerator() &&
op1->enumerator()->value_known)
1059 value = std::to_string(
op1->enumerator()->value);
1064 if (
op2->isExpandedMacro())
1067 if (
op2->enumerator() &&
op2->enumerator()->value_known)
1068 value = std::to_string(
op2->enumerator()->value);
1084 static std::string
conditionString(
bool not1,
const Token *expr1,
const std::string &op,
const std::string &value1)
1086 if (expr1->
astParent()->isComparisonOp())
1104 std::string op, value;
1132 logChecker(
"CheckCondition::checkIncorrectLogicOperator");
1138 if (!
Token::Match(tok,
"%oror%|&&") || !tok->astOperand1() || !tok->astOperand2())
1147 ((tok->str() ==
"||" && tok->astOperand2()->str() ==
"&&") ||
1148 (tok->str() ==
"&&" && tok->astOperand2()->str() ==
"||"))) {
1151 std::string expr1(tok->astOperand1()->expressionString());
1152 std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
1153 std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
1155 const std::string expr1VerboseMsg = expr1;
1156 const std::string expr2VerboseMsg = expr2;
1157 const std::string expr3VerboseMsg = expr3;
1159 if (expr1.length() + expr2.length() + expr3.length() > 50U) {
1160 if (expr1[0] ==
'!' && expr2[0] !=
'!') {
1171 const std::string cond1 = expr1 +
" " + tok->str() +
" (" + expr2 +
" " + tok->astOperand2()->str() +
" " + expr3 +
")";
1172 const std::string cond2 = expr1 +
" " + tok->str() +
" " + expr3;
1174 const std::string cond1VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr2VerboseMsg +
" " + tok->astOperand2()->str() +
" " + expr3VerboseMsg;
1175 const std::string cond2VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr3VerboseMsg;
1177 const std::string msg = tok2->
expressionString() +
". '" + cond1 +
"' is equivalent to '" + cond2 +
"'\n"
1178 "The condition '" + cond1VerboseMsg +
"' is equivalent to '" + cond2VerboseMsg +
"'.";
1183 std::string expr1(tok->astOperand1()->expressionString());
1184 std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
1185 std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
1187 const std::string expr1VerboseMsg = expr1;
1188 const std::string expr2VerboseMsg = expr2;
1189 const std::string expr3VerboseMsg = expr3;
1191 if (expr1.length() + expr2.length() + expr3.length() > 50U) {
1197 const std::string cond1 = expr1 +
" " + tok->str() +
" (" + expr2 +
" " + tok->astOperand2()->str() +
" " + expr3 +
")";
1198 const std::string cond2 = std::move(expr1);
1200 const std::string cond1VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr2VerboseMsg +
" " + tok->astOperand2()->str() +
" " + expr3VerboseMsg;
1201 const std::string& cond2VerboseMsg = expr1VerboseMsg;
1203 const std::string msg = tok2->
expressionString() +
". '" + cond1 +
"' is equivalent to '" + cond2 +
"'\n"
1204 "The condition '" + cond1VerboseMsg +
"' is equivalent to '" + cond2VerboseMsg +
"'.";
1212 if (comp1->
str() == tok->str())
1219 bool parseable =
true;
1223 std::string
op1, value1;
1224 const Token *expr1 =
nullptr;
1229 std::string
op2, value2;
1230 const Token *expr2 =
nullptr;
1246 const bool isLogicalOr(tok->str() ==
"||");
1247 if (!isfloat &&
isOppositeCond(isLogicalOr, tok->astOperand1(), tok->astOperand2(), *
mSettings,
true,
true, &errorPath)) {
1249 const bool alwaysTrue(isLogicalOr);
1266 if (isfloat && (
op1 ==
"==" ||
op1 ==
"!=" ||
op2 ==
"==" ||
op2 ==
"!="))
1274 const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max()==i1) || (std::numeric_limits<MathLib::bigint>::max()==i2);
1278 bool alwaysTrue =
true, alwaysFalse =
true;
1279 bool firstTrue =
true, secondTrue =
true;
1280 const bool isAnd = tok->str() ==
"&&";
1281 for (
int test = 1; test <= 5; ++test) {
1288 bool result1, result2;
1290 const auto testvalue = getvalue<double>(test, d1, d2);
1293 }
else if (useUnsignedInt) {
1294 const auto testvalue = getvalue<MathLib::biguint>(test, u1, u2);
1298 const auto testvalue = getvalue<MathLib::bigint>(test, i1, i2);
1307 alwaysTrue &= (result1 && result2);
1308 alwaysFalse &= !(result1 && result2);
1310 alwaysTrue &= (result1 || result2);
1311 alwaysFalse &= !(result1 || result2);
1313 firstTrue &= !(!result1 && result2);
1314 secondTrue &= !(result1 && !result2);
1319 if (printWarning && (alwaysTrue || alwaysFalse)) {
1320 const std::string text = cond1str +
" " + tok->str() +
" " + cond2str;
1322 }
else if (printStyle && (firstTrue || secondTrue)) {
1324 const int which = isfloat ?
sufficientCondition(std::move(
op1), not1, d1, std::move(
op2), not2, d2, isAnd) :
sufficientCondition(std::move(
op1), not1, i1, std::move(
op2), not2, i2, isAnd);
1327 text =
"The condition '" + (which == 1 ? cond2str : cond1str) +
"' is redundant since '" + (which == 1 ? cond1str : cond2str) +
"' is sufficient.";
1329 text =
"If '" + (secondTrue ? cond1str : cond2str) +
"', the comparison '" + (secondTrue ? cond2str : cond1str) +
"' is always true.";
1340 errors.emplace_back(tok,
"");
1343 "Logical disjunction always evaluates to true: " + condition +
".\n"
1344 "Logical disjunction always evaluates to true: " + condition +
". "
1348 "Logical conjunction always evaluates to false: " + condition +
".\n"
1349 "Logical conjunction always evaluates to false: " + condition +
". "
1368 logChecker(
"CheckCondition::checkModuloAlwaysTrueFalse");
1373 if (!tok->isComparisonOp())
1375 const Token *num, *modulo;
1398 "Comparison of modulo result is predetermined, because it is always less than " + maxVal +
".",
CWE398,
Certainty::normal);
1404 for (
const Token *tok = tok1; tok && tok != tok2; tok = tok->
next()) {
1405 if (tok->str() ==
"(")
1407 else if (tok->str() ==
")")
1409 else if (tok->str() ==
";")
1424 logChecker(
"CheckCondition::clarifyCondition");
1430 for (
const Token *tok2 = tok->
tokAt(3); tok2; tok2 = tok2->
next()) {
1431 if (tok2->str() ==
"(" || tok2->str() ==
"[")
1432 tok2 = tok2->link();
1433 else if (tok2->isComparisonOp()) {
1435 if (!tok2->isC() && tok2->link())
1441 }
else if (!tok2->isName() && !tok2->isNumber() && tok2->str() !=
".")
1444 }
else if (tok->tokType() ==
Token::eBitOp && !tok->isUnaryOp(
"&")) {
1445 if (tok->astOperand2() && tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
1449 const ValueType* vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() :
nullptr;
1450 const ValueType* vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() :
nullptr;
1465 errmsg =
"Suspicious condition (assignment + comparison); Clarify expression with parentheses.";
1468 errmsg =
"Boolean result is used in bitwise operation. Clarify expression with parentheses.\n"
1469 "Suspicious expression. Boolean result is used in bitwise operation. The operator '!' "
1470 "and the comparison operators have higher precedence than bitwise operators. "
1471 "It is recommended that the expression is clarified with parentheses.";
1473 errmsg =
"Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses.\n"
1474 "Suspicious condition. Comparison operators have higher precedence than bitwise operators. "
1475 "Please clarify the condition with parentheses.";
1491 logChecker(
"CheckCondition::alwaysTrueFalse");
1498 Token::Match(tok->previous(),
"static_assert|assert|ASSERT|sizeof|decltype ("))) {
1502 if (!tok->hasKnownIntValue())
1504 if (
Token::Match(tok->previous(),
"%name% (") && tok->previous()->function()) {
1505 const Function* f = tok->previous()->function();
1509 const Token* condition =
nullptr;
1517 if (parent->
str() ==
"?" &&
precedes(tok, parent))
1525 condition = parent->
astParent()->astParent()->previous();
1532 if (
diag(tok,
false))
1549 if (op->hasKnownIntValue() && (!op->isLiteral() || op->isBoolean())) {
1578 const Token *nonZeroExpr =
nullptr;
1585 bool isExpandedMacro =
false;
1590 isExpandedMacro = true;
1591 return ChildrenToVisit::done;
1595 if (isExpandedMacro)
1597 for (
const Token *parent = tok; parent; parent = parent->
astParent()) {
1598 if (parent->isExpandedMacro()) {
1599 isExpandedMacro =
true;
1603 if (isExpandedMacro)
1607 bool hasSizeof =
false;
1615 return ChildrenToVisit::none;
1618 return ChildrenToVisit::op1_and_op2;
1634 const std::string conditionStr = (
Token::simpleMatch(condition,
"return") ?
"Return value" :
"Condition");
1635 const std::string errmsg = conditionStr +
" '" + expr +
"' is always " +
bool_to_string(alwaysTrue);
1639 "knownConditionTrueFalse",
1662 logChecker(
"CheckCondition::checkInvalidTestForOverflow");
1665 if (!
Token::Match(tok,
"<|<=|>=|>") || !tok->isBinaryOp())
1669 for (
const Token *lhs: lhsTokens) {
1670 std::string cmp = tok->str();
1671 if (lhs == tok->astOperand2())
1672 cmp[0] = (cmp[0] ==
'<') ?
'>' :
'<';
1677 const bool isSignedInteger = lhs->valueType() && lhs->valueType()->isIntegral() && lhs->valueType()->sign == ValueType::Sign::SIGNED;
1678 const bool isPointer = lhs->valueType() && lhs->valueType()->pointer > 0;
1679 if (!isSignedInteger && !isPointer)
1683 for (
const Token *expr: exprTokens) {
1684 if (lhs->str() ==
"-" && expr == lhs->astOperand2())
1687 if (expr->hasKnownIntValue())
1704 if (lhs->str() ==
"+")
1705 result = (cmp ==
">" || cmp ==
">=");
1707 result = (cmp ==
"<" || cmp ==
"<=");
1713 if (lhs->str() ==
"+" && other->
varId() > 0) {
1714 const std::string result = other->
str() + cmp +
"0";
1720 if (lhs->str() ==
"-" && other->
varId() > 0) {
1721 std::string cmp2 = cmp;
1722 cmp2[0] = (cmp[0] ==
'<') ?
'>' :
'<';
1723 const std::string result = other->
str() + cmp2 +
"0";
1734 const std::string expr = (tok ? tok->
expressionString() : std::string(
"x + c < x"));
1735 const std::string overflow = (valueType && valueType->
pointer) ?
"pointer overflow" :
"signed integer overflow";
1737 std::string errmsg =
1738 "Invalid test for overflow '" + expr +
"'; " + overflow +
" is undefined behavior.";
1740 errmsg +=
" Some mainstream compilers remove such overflow tests when optimising the code and assume it's always " +
replace +
".";
1742 errmsg +=
" Some mainstream compilers removes handling of overflows when optimising the code and change the code to '" +
replace +
"'.";
1752 logChecker(
"CheckCondition::checkPointerAdditionResultNotNull");
1758 if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
1762 if (tok->isExpandedMacro())
1765 const Token *calcToken, *exprToken;
1766 if (tok->astOperand1()->str() ==
"+") {
1769 }
else if (tok->astOperand2()->str() ==
"+") {
1791 reportError(tok,
Severity::warning,
"pointerAdditionResultNotNull",
"Comparison is wrong. Result of '" + s +
"' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour.");
1799 logChecker(
"CheckCondition::checkDuplicateConditionalAssign");
1810 const bool isBoolVar =
Token::Match(condTok,
"!| %var%");
1815 if (!blockTok->
next())
1822 bool isRedundant =
false;
1824 const bool isNegation = condTok->
str() ==
"!";
1825 const Token*
const varTok = isNegation ? condTok->
next() : condTok;
1827 if (!(vt && vt->
type == ValueType::Type::BOOL && !vt->
pointer))
1835 if (val < 0 || val > 1)
1837 isRedundant = (isNegation && val == 0) || (!isNegation && val == 1);
1854 std::string msg =
"Duplicate expression for the condition and assignment.";
1855 if (condTok && assignTok) {
1856 if (condTok->
str() ==
"==") {
1858 errors.emplace_back(condTok,
"Condition '" + condTok->
expressionString() +
"'");
1859 errors.emplace_back(assignTok,
"Assignment '" + assignTok->
expressionString() +
"' is redundant");
1862 msg += isRedundant ?
"' is redundant." :
"' is logically equivalent to '" + assignTok->
expressionString() +
"'.";
1863 errors.emplace_back(assignTok,
"Assignment '" + assignTok->
expressionString() +
"'");
1864 errors.emplace_back(condTok,
"Condition '" + condTok->
expressionString() +
"' is redundant");
1878 logChecker(
"CheckCondition::checkAssignmentInCondition");
1883 if (tok->str() !=
"=")
1885 if (!tok->astParent())
1889 if (!tok->valueType())
1891 if (tok->valueType()->pointer > 0)
1893 if (tok->valueType()->type != ValueType::Type::CONTAINER && tok->valueType()->type != ValueType::Type::ITERATOR)
1897 if (
Token::Match(tok->astParent()->previous(),
"if|while ("))
1901 else if (
Token::simpleMatch(tok->astParent(),
"?") && tok == tok->astParent()->astOperand1())
1914 "assignmentInCondition",
1915 "Suspicious assignment in condition. Condition '" + expr +
"' is always true.",
1929 logChecker(
"CheckCondition::checkCompareValueOutOfTypeRange");
1934 if (!tok->isComparisonOp() || !tok->isBinaryOp())
1937 for (
int i = 0; i < 2; ++i) {
1938 const Token *
const valueTok = (i == 0) ? tok->
astOperand1() : tok->astOperand2();
1948 case ValueType::Type::BOOL:
1951 case ValueType::Type::CHAR:
1954 case ValueType::Type::SHORT:
1957 case ValueType::Type::INT:
1960 case ValueType::Type::LONG:
1963 case ValueType::Type::LONGLONG:
1969 if (bits == 0 || bits >= 64)
1972 const auto typeMinValue = (typeTok->
valueType()->
sign == ValueType::Sign::UNSIGNED) ? 0 : (-(1LL << (bits-1)));
1973 const auto unsignedTypeMaxValue = (1LL << bits) - 1LL;
1974 long long typeMaxValue;
1976 typeMaxValue = unsignedTypeMaxValue;
1978 typeMaxValue = unsignedTypeMaxValue;
1980 typeMaxValue = unsignedTypeMaxValue / 2;
1984 if (tok->str() ==
"==")
1986 else if (tok->str() ==
"!=")
1988 else if (tok->str()[0] ==
'>' && i == 0)
1991 else if (tok->str()[0] ==
'>' && i == 1)
1994 else if (tok->str()[0] ==
'<' && i == 0)
1997 else if (tok->str()[0] ==
'<' && i == 1)
2002 if (kiv < typeMinValue || kiv > typeMaxValue) {
2007 if (kiv == typeMinValue) {
2008 if (tok->str() ==
"<=") {
2011 }
else if (tok->str() ==
">")
2014 else if (kiv == typeMaxValue && (tok->str() ==
">=" || tok->str() ==
"<")) {
2019 if (kiv == typeMinValue) {
2020 if (tok->str() ==
">=") {
2023 }
else if (tok->str() ==
"<")
2026 else if (kiv == typeMaxValue && (tok->str() ==
"<=" || tok->str() ==
">")) {
2044 "compareValueOutOfTypeRangeError",
2045 "Comparing expression of type '" + type +
"' against value " + std::to_string(value) +
". Condition is always " +
bool_to_string(result) +
".",
static bool isExpressionChangedAt(const F &getExprTok, const Token *tok, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
bool isUsedAsBool(const Token *const tok, const Settings &settings)
Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for.
bool isLikelyStreamRead(const Token *op)
do we see a likely write of rhs through overloaded operator s >> x; a & x;
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
bool isOppositeCond(bool isNot, const Token *const cond1, const Token *const cond2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Are two conditions opposite.
bool isConstVarExpression(const Token *tok, const std::function< bool(const Token *)> &skipPredicate)
bool isWithoutSideEffects(const Token *tok, bool checkArrayAccess, bool checkReference)
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
const Token * nextAfterAstRightmostLeaf(const Token *tok)
bool isVariablesChanged(const Token *start, const Token *end, int indirect, const std::vector< const Variable * > &vars, const Settings &settings)
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
static const CWE CWE571(571U)
static const CWE CWE398(398U)
static bool parseComparison(const Token *comp, bool ¬1, std::string &op, std::string &value, const Token *&expr, bool &inconclusive)
static bool checkFloatRelation(const std::string &op, const double value1, const double value2)
static T getvalue(const int test, const T value1, const T value2)
static bool checkIntRelation(const std::string &op, const T value1, const T value2)
static std::string innerSmtString(const Token *tok)
static const CWE uncheckedErrorConditionCWE(391U)
static const CWE CWE570(570U)
static bool isNonConstFunctionCall(const Token *ftok, const Library &library)
static std::string conditionString(bool not1, const Token *expr1, const std::string &op, const std::string &value1)
static T getvalue3(const T value1, const T value2)
static bool inBooleanFunction(const Token *tok)
static std::string invertOperatorForOperandSwap(std::string s)
static int countPar(const Token *tok1, const Token *tok2)
static bool isOperandExpanded(const Token *tok)
static bool isParameterChanged(const Token *partok)
static bool isIfConstexpr(const Token *tok)
static int sufficientCondition(std::string op1, const bool not1, const T value1, std::string op2, const bool not2, const T value2, const bool isAnd)
static void getnumchildren(const Token *tok, std::list< MathLib::bigint > &numchildren)
static int sign(const T v)
Check for condition mismatches.
void oppositeInnerConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
void checkInvalidTestForOverflow()
Check for invalid test for overflow 'x+100 < x'
void checkIncorrectLogicOperator()
Check for testing for mutual exclusion over ||
void comparison()
mismatching lhs and rhs in comparison
std::set< const Token * > mCondDiags
void multiCondition()
match 'if' and 'else if' conditions
void assignIf()
mismatching assignment / comparison
bool assignIfParseScope(const Token *const assignTok, const Token *const startTok, const nonneg int varid, const bool islocal, const char bitop, const MathLib::bigint num)
parse scopes recursively
void invalidTestForOverflow(const Token *tok, const ValueType *valueType, const std::string &replace)
void checkPointerAdditionResultNotNull()
Check if pointer addition result is NULL '(ptr + 1) == NULL'.
void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result)
void redundantConditionError(const Token *tok, const std::string &text, bool inconclusive)
void oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath)
void alwaysTrueFalseError(const Token *tok, const Token *condition, const ValueFlow::Value *value)
void identicalConditionAfterEarlyExitError(const Token *cond1, const Token *cond2, ErrorPath errorPath)
void assignmentInCondition(const Token *eq)
void multiCondition2()
multiconditions #2
void badBitmaskCheckError(const Token *tok, bool isNoOp=false)
void identicalInnerConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
void duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
bool isOverlappingCond(const Token *const cond1, const Token *const cond2, bool pure) const
void moduloAlwaysTrueFalseError(const Token *tok, const std::string &maxVal)
void checkModuloAlwaysTrueFalse()
Check for suspicious usage of modulo (e.g.
void clarifyConditionError(const Token *tok, bool assign, bool boolop)
bool isAliased(const std::set< int > &vars) const
void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2)
void clarifyCondition()
Suspicious condition (assignment+comparison)
void duplicateConditionalAssignError(const Token *condTok, const Token *assignTok, bool isRedundant=false)
void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors)
void compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, long long value, bool result)
void checkDuplicateConditionalAssign()
void alwaysTrueFalse()
Condition is always true/false.
void overlappingElseIfConditionError(const Token *tok, nonneg int line1)
void comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)
void pointerAdditionResultNotNullError(const Token *tok, const Token *calc)
bool diag(const Token *tok, bool insert=true)
void checkCompareValueOutOfTypeRange()
void checkAssignmentInCondition()
Assignment in condition.
void duplicateCondition()
void checkBadBitmaskCheck()
check bitmask using | instead of &
static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr)
Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is positive?
static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress=false)
Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero?
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
ErrorPath getErrorPath(const Token *errtok, const ValueFlow::Value *value, std::string bug) const
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
const Scope * functionScope
scope of function body
const Token * retDef
function return type token
Library definitions handling.
bool isFunctionConst(const std::string &functionName, bool pure) const
static bool isLessEqual(const std::string &first, const std::string &second)
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
static bool isFloat(const std::string &str)
static bool isNegative(const std::string &str)
static bool isInt(const std::string &str)
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
unsigned long long biguint
Function * function
function info for this function
const Token * classDef
class/struct/union/namespace token
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
The token list that the TokenList generates is a linked-list of this class.
const ValueFlow::Value * getValue(const MathLib::bigint val) const
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
bool isEnumerator() const
bool hasKnownIntValue() const
MathLib::bigint getKnownIntValue() const
bool isExpandedMacro() const
bool isArithmeticalOp() const
const ValueType * valueType() const
const std::string & strAt(int index) const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
std::string expressionString() const
bool isUnaryOp(const std::string &s) const
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
nonneg int linenr() const
void variable(const Variable *v)
Associate this token with given variable.
bool isComparisonOp() const
const std::list< ValueFlow::Value > & values() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
void astParent(Token *tok)
const Token * tokens() const
const SymbolDatabase * getSymbolDatabase() const
bool hasIfdef(const Token *start, const Token *end) const
bool isImpossible() const
long long intvalue
int value (or sometimes bool value?)
enum ValueType::Type type
bool isTypeEqual(const ValueType *that) const
Check if type is the same ignoring const and references.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
enum ValueType::Sign sign
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isReference() const
Is reference variable.
bool isLocal() const
Is variable local.
bool isConst() const
Is variable const.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isPointer() const
Is pointer variable.
static void replace(std::string &source, const std::unordered_map< std::string, std::string > &substitutionMap)
std::list< ErrorPathItem > ErrorPath
@ error
Programming error.
static bool isTrue(const ValueFlow::Value &v)
static const char * bool_to_string(bool b)