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() ==
".")
619 logChecker(
"CheckCondition::multiCondition2");
624 const Token *condTok =
nullptr;
629 if (!condTok || condTok->
str() !=
";")
632 if (!condTok || condTok->
str() !=
";")
638 const Token *
const cond1 = condTok;
643 bool functionCall =
false;
644 bool nonConstFunctionCall =
false;
645 bool nonlocal =
false;
648 [&](
const Token *cond) {
652 if (nonConstFunctionCall)
657 vars.insert(cond->
varId());
659 if (!nonlocal && var) {
666 }
else if (!nonlocal && cond->
isName()) {
675 if (nonConstFunctionCall)
678 std::vector<const Variable*> varsInCond;
680 [&varsInCond](
const Token *cond) {
682 const Variable *var = cond->variable();
683 if (std::find(varsInCond.cbegin(), varsInCond.cend(), var) == varsInCond.cend())
684 varsInCond.push_back(var);
690 enum MULTICONDITIONTYPE { INNER, AFTER };
694 std::vector<MULTICONDITIONTYPE> types = {MULTICONDITIONTYPE::INNER};
696 types.push_back(MULTICONDITIONTYPE::AFTER);
697 for (
const MULTICONDITIONTYPE type:types) {
698 if (type == MULTICONDITIONTYPE::AFTER) {
703 const Token *
const endToken = tok->
scope()->bodyEnd;
705 for (; tok && tok != endToken; tok = tok->
next()) {
709 const Token * condStartToken = tok->
str() ==
"if" ? tok->
next() : tok;
717 const bool isReturnVar = (tok->
str() ==
"return" && !
Token::Match(cond2,
"%cop%"));
721 if (type == MULTICONDITIONTYPE::INNER) {
725 if (firstCondition->
str() ==
"&&") {
726 if (!isOppositeCond(false, firstCondition, cond2, *mSettings, true, true))
727 return ChildrenToVisit::op1_and_op2;
730 if (!isReturnVar && isOppositeCond(false, firstCondition, cond2, *mSettings, true, true, &errorPath)) {
731 if (!isAliased(vars))
732 oppositeInnerConditionError(firstCondition, cond2, errorPath);
741 if (secondCondition->
str() ==
"||" || secondCondition->
str() ==
"&&")
747 identicalConditionAfterEarlyExitError(cond1, secondCondition, errorPath);
748 return ChildrenToVisit::done;
784 const bool changed = std::any_of(vars.cbegin(), vars.cend(), [&](
int varid) {
785 return isVariableChanged(tok1, tok2, varid, nonlocal, *mSettings);
790 if ((tok->
varId() && vars.find(tok->
varId()) != vars.end()) ||
791 (!tok->
varId() && nonlocal) ||
796 const Token *parent = tok;
819 if (!
function || !function->isConst())
849 errorPath.emplace_back(tok1,
"outer condition: " + s1);
850 errorPath.emplace_back(tok2,
"opposite inner condition: " + s2);
852 const std::string msg(
"Opposite inner '" + innerSmt +
"' condition leads to a dead code block.\n"
853 "Opposite inner '" + innerSmt +
"' condition leads to a dead code block (outer condition is '" + s1 +
"' and inner condition is '" + s2 +
"').");
864 errorPath.emplace_back(tok1,
"outer condition: " + s1);
865 errorPath.emplace_back(tok2,
"identical inner condition: " + s2);
867 const std::string msg(
"Identical inner '" + innerSmt +
"' condition is always true.\n"
868 "Identical inner '" + innerSmt +
"' condition is always true (outer condition is '" + s1 +
"' and inner condition is '" + s2 +
"').");
880 const std::string value = (cond2 && cond2->
valueType() && cond2->
valueType()->
type == ValueType::Type::BOOL) ?
"false" :
"0";
882 errorPath.emplace_back(cond1,
"If condition '" + cond +
"' is true, the function will return/exit");
883 errorPath.emplace_back(cond2, (isReturnValue ?
"Returning identical expression '" :
"Testing identical condition '") + cond +
"'");
887 "identicalConditionAfterEarlyExit",
889 ? (
"Identical condition and return expression '" + cond +
"', return value is always " + value)
890 : (
"Identical condition '" + cond +
"', second condition is always false"),
916 else if (s[0] ==
'>')
923 return static_cast<int>(v > 0) -
static_cast<int>(v < 0);
928 static int sufficientCondition(std::string op1,
const bool not1,
const T value1, std::string op2,
const bool not2,
const T value2,
const bool isAnd) {
929 auto transformOp = [](std::string& op,
const bool invert) {
945 transformOp(
op1, not1);
946 transformOp(
op2, not2);
951 if (
op1 ==
">" ||
op1 ==
">=")
952 res =
sign(value1 - value2);
953 else if (
op1 ==
"<" ||
op1 ==
"<=")
954 res = -
sign(value1 - value2);
958 else if (
op2 ==
"!=")
960 else if (
op1 ==
"==")
962 else if (
op2 ==
"==")
964 else if (
op1 ==
">" &&
op2 ==
">=")
965 res =
sign(value1 - (value2 - 1));
966 else if (
op1 ==
">=" &&
op2 ==
">")
967 res =
sign((value1 - 1) - value2);
968 else if (
op1 ==
"<" &&
op2 ==
"<=")
969 res = -
sign(value1 - (value2 + 1));
970 else if (
op1 ==
"<=" &&
op2 ==
"<")
971 res = -
sign((value1 + 1) - value2);
973 return res * (isAnd == equal ? 1 : -1);
979 return (op ==
"==" && value1 == value2) ||
980 (op ==
"!=" && value1 != value2) ||
981 (op ==
">" && value1 > value2) ||
982 (op ==
">=" && value1 >= value2) ||
983 (op ==
"<" && value1 < value2) ||
984 (op ==
"<=" && value1 <= value2);
989 return (op ==
">" && value1 > value2) ||
990 (op ==
">=" && value1 >= value2) ||
991 (op ==
"<" && value1 < value2) ||
992 (op ==
"<=" && value1 <= value2);
998 const T min = std::min(value1, value2);
999 if (min== std::numeric_limits<T>::max())
1007 return (value1 + value2) / 2.0;
1012 static inline T
getvalue(
const int test,
const T value1,
const T value2)
1022 return std::numeric_limits<T>::lowest();
1026 return getvalue3<T>(value1, value2);
1030 return std::numeric_limits<T>::max();
1038 while (comp && comp->
str() ==
"!") {
1052 }
else if (
op1->isLiteral()) {
1053 if (
op1->isExpandedMacro())
1056 if (
op1->enumerator() &&
op1->enumerator()->value_known)
1057 value = std::to_string(
op1->enumerator()->value);
1062 if (
op2->isExpandedMacro())
1065 if (
op2->enumerator() &&
op2->enumerator()->value_known)
1066 value = std::to_string(
op2->enumerator()->value);
1082 static std::string
conditionString(
bool not1,
const Token *expr1,
const std::string &op,
const std::string &value1)
1084 if (expr1->
astParent()->isComparisonOp())
1102 std::string op, value;
1130 logChecker(
"CheckCondition::checkIncorrectLogicOperator");
1136 if (!
Token::Match(tok,
"%oror%|&&") || !tok->astOperand1() || !tok->astOperand2())
1145 ((tok->str() ==
"||" && tok->astOperand2()->str() ==
"&&") ||
1146 (tok->str() ==
"&&" && tok->astOperand2()->str() ==
"||"))) {
1149 std::string expr1(tok->astOperand1()->expressionString());
1150 std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
1151 std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
1153 const std::string expr1VerboseMsg = expr1;
1154 const std::string expr2VerboseMsg = expr2;
1155 const std::string expr3VerboseMsg = expr3;
1157 if (expr1.length() + expr2.length() + expr3.length() > 50U) {
1158 if (expr1[0] ==
'!' && expr2[0] !=
'!') {
1169 const std::string cond1 = expr1 +
" " + tok->str() +
" (" + expr2 +
" " + tok->astOperand2()->str() +
" " + expr3 +
")";
1170 const std::string cond2 = expr1 +
" " + tok->str() +
" " + expr3;
1172 const std::string cond1VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr2VerboseMsg +
" " + tok->astOperand2()->str() +
" " + expr3VerboseMsg;
1173 const std::string cond2VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr3VerboseMsg;
1175 const std::string msg = tok2->
expressionString() +
". '" + cond1 +
"' is equivalent to '" + cond2 +
"'\n"
1176 "The condition '" + cond1VerboseMsg +
"' is equivalent to '" + cond2VerboseMsg +
"'.";
1181 std::string expr1(tok->astOperand1()->expressionString());
1182 std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
1183 std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
1185 const std::string expr1VerboseMsg = expr1;
1186 const std::string expr2VerboseMsg = expr2;
1187 const std::string expr3VerboseMsg = expr3;
1189 if (expr1.length() + expr2.length() + expr3.length() > 50U) {
1195 const std::string cond1 = expr1 +
" " + tok->str() +
" (" + expr2 +
" " + tok->astOperand2()->str() +
" " + expr3 +
")";
1196 const std::string cond2 = std::move(expr1);
1198 const std::string cond1VerboseMsg = expr1VerboseMsg +
" " + tok->str() +
" " + expr2VerboseMsg +
" " + tok->astOperand2()->str() +
" " + expr3VerboseMsg;
1199 const std::string& cond2VerboseMsg = expr1VerboseMsg;
1201 const std::string msg = tok2->
expressionString() +
". '" + cond1 +
"' is equivalent to '" + cond2 +
"'\n"
1202 "The condition '" + cond1VerboseMsg +
"' is equivalent to '" + cond2VerboseMsg +
"'.";
1210 if (comp1->
str() == tok->str())
1217 bool parseable =
true;
1221 std::string
op1, value1;
1222 const Token *expr1 =
nullptr;
1227 std::string
op2, value2;
1228 const Token *expr2 =
nullptr;
1244 const bool isLogicalOr(tok->str() ==
"||");
1245 if (!isfloat &&
isOppositeCond(isLogicalOr, tok->astOperand1(), tok->astOperand2(), *
mSettings,
true,
true, &errorPath)) {
1247 const bool alwaysTrue(isLogicalOr);
1264 if (isfloat && (
op1 ==
"==" ||
op1 ==
"!=" ||
op2 ==
"==" ||
op2 ==
"!="))
1272 const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max()==i1) || (std::numeric_limits<MathLib::bigint>::max()==i2);
1276 bool alwaysTrue =
true, alwaysFalse =
true;
1277 bool firstTrue =
true, secondTrue =
true;
1278 const bool isAnd = tok->str() ==
"&&";
1279 for (
int test = 1; test <= 5; ++test) {
1286 bool result1, result2;
1288 const auto testvalue = getvalue<double>(test, d1, d2);
1291 }
else if (useUnsignedInt) {
1292 const auto testvalue = getvalue<MathLib::biguint>(test, u1, u2);
1296 const auto testvalue = getvalue<MathLib::bigint>(test, i1, i2);
1305 alwaysTrue &= (result1 && result2);
1306 alwaysFalse &= !(result1 && result2);
1308 alwaysTrue &= (result1 || result2);
1309 alwaysFalse &= !(result1 || result2);
1311 firstTrue &= !(!result1 && result2);
1312 secondTrue &= !(result1 && !result2);
1317 if (printWarning && (alwaysTrue || alwaysFalse)) {
1318 const std::string text = cond1str +
" " + tok->str() +
" " + cond2str;
1320 }
else if (printStyle && (firstTrue || secondTrue)) {
1322 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);
1325 text =
"The condition '" + (which == 1 ? cond2str : cond1str) +
"' is redundant since '" + (which == 1 ? cond1str : cond2str) +
"' is sufficient.";
1327 text =
"If '" + (secondTrue ? cond1str : cond2str) +
"', the comparison '" + (secondTrue ? cond2str : cond1str) +
"' is always true.";
1338 errors.emplace_back(tok,
"");
1341 "Logical disjunction always evaluates to true: " + condition +
".\n"
1342 "Logical disjunction always evaluates to true: " + condition +
". "
1346 "Logical conjunction always evaluates to false: " + condition +
".\n"
1347 "Logical conjunction always evaluates to false: " + condition +
". "
1366 logChecker(
"CheckCondition::checkModuloAlwaysTrueFalse");
1371 if (!tok->isComparisonOp())
1373 const Token *num, *modulo;
1396 "Comparison of modulo result is predetermined, because it is always less than " + maxVal +
".",
CWE398,
Certainty::normal);
1402 for (
const Token *tok = tok1; tok && tok != tok2; tok = tok->
next()) {
1403 if (tok->str() ==
"(")
1405 else if (tok->str() ==
")")
1407 else if (tok->str() ==
";")
1422 logChecker(
"CheckCondition::clarifyCondition");
1428 for (
const Token *tok2 = tok->
tokAt(3); tok2; tok2 = tok2->
next()) {
1429 if (tok2->str() ==
"(" || tok2->str() ==
"[")
1430 tok2 = tok2->link();
1431 else if (tok2->isComparisonOp()) {
1433 if (!tok2->isC() && tok2->link())
1439 }
else if (!tok2->isName() && !tok2->isNumber() && tok2->str() !=
".")
1442 }
else if (tok->tokType() ==
Token::eBitOp && !tok->isUnaryOp(
"&")) {
1443 if (tok->astOperand2() && tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
1447 const ValueType* vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() :
nullptr;
1448 const ValueType* vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() :
nullptr;
1463 errmsg =
"Suspicious condition (assignment + comparison); Clarify expression with parentheses.";
1466 errmsg =
"Boolean result is used in bitwise operation. Clarify expression with parentheses.\n"
1467 "Suspicious expression. Boolean result is used in bitwise operation. The operator '!' "
1468 "and the comparison operators have higher precedence than bitwise operators. "
1469 "It is recommended that the expression is clarified with parentheses.";
1471 errmsg =
"Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses.\n"
1472 "Suspicious condition. Comparison operators have higher precedence than bitwise operators. "
1473 "Please clarify the condition with parentheses.";
1488 logChecker(
"CheckCondition::alwaysTrueFalse");
1495 Token::Match(tok->previous(),
"static_assert|assert|ASSERT|sizeof|decltype ("))) {
1499 if (!tok->hasKnownIntValue())
1501 if (
Token::Match(tok->previous(),
"%name% (") && tok->previous()->function()) {
1502 const Function* f = tok->previous()->function();
1506 const Token* condition =
nullptr;
1514 if (parent->
str() ==
"?" &&
precedes(tok, parent))
1522 condition = parent->
astParent()->astParent()->previous();
1529 if (
diag(tok,
false))
1546 if (op->hasKnownIntValue() && (!op->isLiteral() || op->isBoolean())) {
1575 const Token *nonZeroExpr =
nullptr;
1582 bool isExpandedMacro =
false;
1587 isExpandedMacro = true;
1588 return ChildrenToVisit::done;
1592 if (isExpandedMacro)
1594 for (
const Token *parent = tok; parent; parent = parent->
astParent()) {
1595 if (parent->isExpandedMacro()) {
1596 isExpandedMacro =
true;
1600 if (isExpandedMacro)
1604 bool hasSizeof =
false;
1612 return ChildrenToVisit::none;
1615 return ChildrenToVisit::op1_and_op2;
1631 const std::string conditionStr = (
Token::simpleMatch(condition,
"return") ?
"Return value" :
"Condition");
1632 const std::string errmsg = conditionStr +
" '" + expr +
"' is always " +
bool_to_string(alwaysTrue);
1636 "knownConditionTrueFalse",
1659 logChecker(
"CheckCondition::checkInvalidTestForOverflow");
1662 if (!
Token::Match(tok,
"<|<=|>=|>") || !tok->isBinaryOp())
1666 for (
const Token *lhs: lhsTokens) {
1667 std::string cmp = tok->str();
1668 if (lhs == tok->astOperand2())
1669 cmp[0] = (cmp[0] ==
'<') ?
'>' :
'<';
1674 const bool isSignedInteger = lhs->valueType() && lhs->valueType()->isIntegral() && lhs->valueType()->sign == ValueType::Sign::SIGNED;
1675 const bool isPointer = lhs->valueType() && lhs->valueType()->pointer > 0;
1676 if (!isSignedInteger && !isPointer)
1680 for (
const Token *expr: exprTokens) {
1681 if (lhs->str() ==
"-" && expr == lhs->astOperand2())
1684 if (expr->hasKnownIntValue())
1701 if (lhs->str() ==
"+")
1702 result = (cmp ==
">" || cmp ==
">=");
1704 result = (cmp ==
"<" || cmp ==
"<=");
1710 if (lhs->str() ==
"+" && other->
varId() > 0) {
1711 const std::string result = other->
str() + cmp +
"0";
1717 if (lhs->str() ==
"-" && other->
varId() > 0) {
1718 std::string cmp2 = cmp;
1719 cmp2[0] = (cmp[0] ==
'<') ?
'>' :
'<';
1720 const std::string result = other->
str() + cmp2 +
"0";
1731 const std::string expr = (tok ? tok->
expressionString() : std::string(
"x + c < x"));
1732 const std::string overflow = (valueType && valueType->
pointer) ?
"pointer overflow" :
"signed integer overflow";
1734 std::string errmsg =
1735 "Invalid test for overflow '" + expr +
"'; " + overflow +
" is undefined behavior.";
1737 errmsg +=
" Some mainstream compilers remove such overflow tests when optimising the code and assume it's always " +
replace +
".";
1739 errmsg +=
" Some mainstream compilers removes handling of overflows when optimising the code and change the code to '" +
replace +
"'.";
1749 logChecker(
"CheckCondition::checkPointerAdditionResultNotNull");
1755 if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
1759 if (tok->isExpandedMacro())
1762 const Token *calcToken, *exprToken;
1763 if (tok->astOperand1()->str() ==
"+") {
1766 }
else if (tok->astOperand2()->str() ==
"+") {
1788 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.");
1796 logChecker(
"CheckCondition::checkDuplicateConditionalAssign");
1807 const bool isBoolVar =
Token::Match(condTok,
"!| %var%");
1812 if (!blockTok->
next())
1819 bool isRedundant =
false;
1821 const bool isNegation = condTok->
str() ==
"!";
1822 const Token*
const varTok = isNegation ? condTok->
next() : condTok;
1824 if (!(vt && vt->
type == ValueType::Type::BOOL && !vt->
pointer))
1832 if (val < 0 || val > 1)
1834 isRedundant = (isNegation && val == 0) || (!isNegation && val == 1);
1851 std::string msg =
"Duplicate expression for the condition and assignment.";
1852 if (condTok && assignTok) {
1853 if (condTok->
str() ==
"==") {
1855 errors.emplace_back(condTok,
"Condition '" + condTok->
expressionString() +
"'");
1856 errors.emplace_back(assignTok,
"Assignment '" + assignTok->
expressionString() +
"' is redundant");
1859 msg += isRedundant ?
"' is redundant." :
"' is logically equivalent to '" + assignTok->
expressionString() +
"'.";
1860 errors.emplace_back(assignTok,
"Assignment '" + assignTok->
expressionString() +
"'");
1861 errors.emplace_back(condTok,
"Condition '" + condTok->
expressionString() +
"' is redundant");
1875 logChecker(
"CheckCondition::checkAssignmentInCondition");
1880 if (tok->str() !=
"=")
1882 if (!tok->astParent())
1886 if (!tok->valueType())
1888 if (tok->valueType()->pointer > 0)
1890 if (tok->valueType()->type != ValueType::Type::CONTAINER && tok->valueType()->type != ValueType::Type::ITERATOR)
1894 if (
Token::Match(tok->astParent()->previous(),
"if|while ("))
1898 else if (
Token::simpleMatch(tok->astParent(),
"?") && tok == tok->astParent()->astOperand1())
1911 "assignmentInCondition",
1912 "Suspicious assignment in condition. Condition '" + expr +
"' is always true.",
1926 logChecker(
"CheckCondition::checkCompareValueOutOfTypeRange");
1931 if (!tok->isComparisonOp() || !tok->isBinaryOp())
1934 for (
int i = 0; i < 2; ++i) {
1935 const Token *
const valueTok = (i == 0) ? tok->
astOperand1() : tok->astOperand2();
1945 case ValueType::Type::BOOL:
1948 case ValueType::Type::CHAR:
1951 case ValueType::Type::SHORT:
1954 case ValueType::Type::INT:
1957 case ValueType::Type::LONG:
1960 case ValueType::Type::LONGLONG:
1966 if (bits == 0 || bits >= 64)
1969 const auto typeMinValue = (typeTok->
valueType()->
sign == ValueType::Sign::UNSIGNED) ? 0 : (-(1LL << (bits-1)));
1970 const auto unsignedTypeMaxValue = (1LL << bits) - 1LL;
1971 long long typeMaxValue;
1973 typeMaxValue = unsignedTypeMaxValue;
1975 typeMaxValue = unsignedTypeMaxValue;
1977 typeMaxValue = unsignedTypeMaxValue / 2;
1981 if (tok->str() ==
"==")
1983 else if (tok->str() ==
"!=")
1985 else if (tok->str()[0] ==
'>' && i == 0)
1988 else if (tok->str()[0] ==
'>' && i == 1)
1991 else if (tok->str()[0] ==
'<' && i == 0)
1994 else if (tok->str()[0] ==
'<' && i == 1)
1999 if (kiv < typeMinValue || kiv > typeMaxValue) {
2004 if (kiv == typeMinValue) {
2005 if (tok->str() ==
"<=") {
2008 }
else if (tok->str() ==
">")
2011 else if (kiv == typeMaxValue && (tok->str() ==
">=" || tok->str() ==
"<")) {
2016 if (kiv == typeMinValue) {
2017 if (tok->str() ==
">=") {
2020 }
else if (tok->str() ==
"<")
2023 else if (kiv == typeMaxValue && (tok->str() ==
"<=" || tok->str() ==
">")) {
2041 "compareValueOutOfTypeRangeError",
2042 "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
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)