44 #include <unordered_map> 
  138         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
  143             const Token* accessTok = parent;
 
  152                 if (!value.isContainerSizeValue())
 
  154                 if (value.isImpossible())
 
  160                 if (value.intvalue == 0 && (indexTok ||
 
  163                     std::string indexExpr;
 
  170                     std::vector<ValueFlow::Value> indexValues =
 
  172                     if (!indexValues.empty()) {
 
  182                     if (!v.isSymbolicValue())
 
  184                     if (v.isImpossible())
 
  188                     const Token* sizeTok = v.tokvalue;
 
  189                     if (sizeTok && sizeTok->isCast())
 
  190                         sizeTok = sizeTok->astOperand2() ? sizeTok->astOperand2() : sizeTok->astOperand1();
 
  191                     const Token* containerTok = getContainerFromSize(container, sizeTok);
 
  194                     return containerTok->exprId() == tok->exprId();
 
  207         return "at position " + std::to_string(indexValue.
intvalue) + 
" from the beginning";
 
  209         return "at position " + std::to_string(-indexValue.
intvalue) + 
" from the end";
 
  210     std::string indexString = std::to_string(indexValue.
intvalue);
 
  212         indexString = containerName + 
".size()";
 
  214             indexString += 
"+" + std::to_string(indexValue.
intvalue);
 
  217         return "greater or equal to " + indexString;
 
  227     const std::string expression = tok ? tok->
expressionString() : (containerName+
"[x]");
 
  230     if (!containerSize) {
 
  233                      "' can have the value " + 
indexValueString(*indexValue, containerName) + 
". Expression '" +
 
  234                      expression + 
"' causes access out of bounds.";
 
  236             errmsg = 
"Out of bounds access in expression '" + expression + 
"'";
 
  237     } 
else if (containerSize->
intvalue == 0) {
 
  241             errmsg = 
"Out of bounds access in expression '" + expression + 
"' because '$symbol' is empty and '" + index + 
"' may be non-zero.";
 
  243             errmsg = 
"Out of bounds access in expression '" + expression + 
"' because '$symbol' is empty.";
 
  244     } 
else if (indexValue) {
 
  250             errmsg = 
"Out of bounds access in '" + expression + 
"', if '$symbol' size is " + std::to_string(containerSize->
intvalue) + 
" and '" + index + 
"' is " + 
indexValueString(*indexValue);
 
  258         errorPath = 
getErrorPath(tok, containerSize, 
"Access out of bounds");
 
  262         if (errorPath1.size() <= 1)
 
  263             errorPath = std::move(errorPath2);
 
  264         else if (errorPath2.size() <= 1)
 
  265             errorPath = std::move(errorPath1);
 
  267             errorPath = std::move(errorPath1);
 
  268             errorPath.splice(errorPath.end(), errorPath2);
 
  274                 "containerOutOfBounds",
 
  275                 "$symbol:" + containerName +
"\n" + errmsg,
 
  297     if (expr->
str() == 
"*") {
 
  307     if (expr->
str() == 
"+") {
 
  322     logChecker(
"CheckStl::outOfBoundsIndexExpression");
 
  324         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
  325             if (!tok->isName() || !tok->valueType())
 
  342     const std::string varname = tok ? tok->
str() : std::string(
"var");
 
  343     const std::string i = index ? index->
expressionString() : std::string(varname + 
".size()");
 
  345     std::string errmsg = 
"Out of bounds access of $symbol, index '" + i + 
"' is out of bounds.";
 
  349                 "containerOutOfBoundsIndexExpression",
 
  350                 "$symbol:" + varname +
"\n" + errmsg,
 
  366                 "$symbol:" + containerName1 + 
"\n" 
  367                 "$symbol:" + containerName2 + 
"\n" 
  368                 "Same iterator is used with different containers '" + containerName1 + 
"' and '" + containerName2 + 
"'.", 
CWE664, 
Certainty::normal);
 
  373     std::list<const Token*> callstack = { tok, containerTok };
 
  375                 "$symbol:" + containerName1 + 
"\n" 
  376                 "$symbol:" + containerName2 + 
"\n" 
  377                 "Same iterator is used with different containers '" + containerName1 + 
"' and '" + containerName2 + 
"'.", 
CWE664, 
Certainty::normal);
 
  382     std::list<const Token*> callstack = { tok, containerTok };
 
  386                 "$symbol:" + containerName +
 
  388                 "Same iterator is used with containers '$symbol' that are temporaries or defined in different scopes.",
 
  397         std::list<const Token*> callstack = { deref, erased };
 
  399                     "$symbol:" + itername + 
"\n" 
  400                     "Iterator '$symbol' used after element has been erased.\n" 
  401                     "The iterator '$symbol' is invalid after the element it pointed to has been erased. " 
  405                     "$symbol:" + itername + 
"\n" 
  406                     "Invalid iterator '$symbol' used.\n" 
  407                     "The iterator '$symbol' is invalid before being assigned. " 
  425     inconclusiveType = 
false;
 
  433         if (!end || end->
argCount() > 0 || !incOperator)
 
  436         inconclusiveType = 
true; 
 
  445         return std::string();
 
  446     std::string ret(containerToken->
str());
 
  447     for (
const Token *nametok = containerToken; nametok; nametok = nametok->
tokAt(-2)) {
 
  450         ret = nametok->strAt(-2) + 
'.' + ret;
 
  471     std::map<int, const Token*> iteratorScopeBeginInfo;
 
  473         bool inconclusiveType=
false;
 
  476         const int iteratorId = var->declarationId();
 
  478             iteratorScopeBeginInfo[iteratorId] = var->nameToken();
 
  482         bool inconclusiveType=
false;
 
  488         const int iteratorId = var->declarationId();
 
  491         bool validIterator = 
Token::Match(var->nameToken()->next(), 
"[(=:{]");
 
  492         const Scope* invalidationScope = 
nullptr;
 
  495         const Token* containerToken = 
nullptr;
 
  496         const Scope* containerAssignScope = 
nullptr;
 
  499         const Token* validatingToken = 
nullptr;
 
  501         const Token* eraseToken = 
nullptr;
 
  505         for (
const Token *tok2 = var->nameToken(); tok2 && tok2 != var->
scope()->bodyEnd; tok2 = tok2->next()) {
 
  506             if (invalidationScope && tok2 == invalidationScope->
bodyEnd)
 
  507                 validIterator = 
true; 
 
  508             if (containerAssignScope && tok2 == containerAssignScope->
bodyEnd)
 
  509                 containerToken = 
nullptr; 
 
  511             if (tok2 == validatingToken) {
 
  512                 validIterator = 
true;
 
  513                 eraseToken = 
nullptr;
 
  514                 invalidationScope = 
nullptr;
 
  518             if (
Token::Match(tok2, 
"%name% . insert|erase ( *| %varid% )|,", iteratorId) && !
isVector(tok2)) {
 
  520                 if (itTok->
str() == 
"*") {
 
  521                     if (tok2->strAt(2) == 
"insert")
 
  524                     itTok = itTok->
next();
 
  532                 if (containerToken && tok2->
varId() != containerToken->
varId()) {
 
  534                     const Variable *variableInfo = tok2->variable();
 
  545                     if (tok2->strAt(2) == 
"insert") {
 
  549                         while (par2->
str() != 
")") {
 
  552                             bool inconclusiveType2=
false;
 
  555                             if (par2->
str() == 
"(")
 
  559                         if (par2->
str() != 
")")
 
  564                     if (containerToken && containerToken->
variable() && containerToken->
variable()->isReference()) {
 
  565                         const Token *nameToken = containerToken->
variable()->nameToken();
 
  568                             const Token *name2 = tok2;
 
  570                                 name1 = name1->
next();
 
  571                                 name2 = name2->
next();
 
  583                 else if (tok2->strAt(2) == 
"erase" && (tok2->strAt(4) != 
"*" || (containerToken && tok2->
varId() == containerToken->
varId()))) {
 
  584                     validIterator = 
false;
 
  586                     invalidationScope = tok2->scope();
 
  590                 tok2 = itTok->
next();
 
  595             else if (
Token::Match(tok2, 
"%varid% = %name% .", iteratorId) &&
 
  599                 tok2 = validatingToken->
link();
 
  603             else if (
Token::Match(tok2, 
"%varid% = %name% .", iteratorId) &&
 
  608                     containerToken = 
nullptr;
 
  609                 containerAssignScope = tok2->scope();
 
  612                 tok2 = validatingToken->
link();
 
  621             else if (
Token::Match(tok2, 
"%varid% ,|)", iteratorId)) {
 
  622                 validIterator = 
true;
 
  626             else if (!validIterator && 
Token::Match(tok2, 
"* %varid%", iteratorId)) {
 
  629             } 
else if (!validIterator && 
Token::Match(tok2, 
"%varid% . %name%", iteratorId)) {
 
  631                 tok2 = tok2->tokAt(2);
 
  636             else if (tok2->scope() == invalidationScope && 
Token::Match(tok2, 
"return|break|continue")) {
 
  642             else if (tok2->str() == 
"else") {
 
  643                 validIterator = 
true;
 
  651     const std::string container(containerTok ? containerTok->
expressionString() : std::string(
"v1"));
 
  652     const std::string container2(containerTok2 ? containerTok2->
expressionString() : std::string(
"v2"));
 
  653     const std::string iter(iterTok ? iterTok->
expressionString() : std::string(
"it"));
 
  656                 "mismatchingContainerIterator",
 
  657                 "Iterator '" + iter + 
"' referring to container '" + container2 + 
"' is used with container '" + container + 
"'.",
 
  665     const std::string expr1(tok1 ? tok1->
expressionString() : std::string(
"v1"));
 
  666     const std::string expr2(tok2 ? tok2->
expressionString() : std::string(
"v2"));
 
  669                 "mismatchingContainers",
 
  670                 "Iterators of different containers '" + expr1 + 
"' and '" + expr2 + 
"' are used together.",
 
  677     const std::string expr1(tok1 ? tok1->
expressionString() : std::string(
"v1"));
 
  678     const std::string expr2(tok2 ? tok2->
expressionString() : std::string(
"v2"));
 
  680                 "Iterators to containers from different expressions '" +
 
  696     std::vector<const Token*> res;
 
  697     for (
const auto& v : values) {
 
  699             res.emplace_back(v.tokvalue);
 
  702         res.emplace_back(tok);
 
  719         return std::any_of(address1.begin(), address1.end(), [&](
const Token* tok1) {
 
  720             return std::any_of(address2.begin(), address2.end(), [&](const Token* tok2) {
 
  721                 return isSameExpression(false, tok1, tok2, settings, false, false);
 
  730     auto findIterVal = [](
const std::vector<ValueFlow::Value>& values, 
const std::vector<ValueFlow::Value>::const_iterator beg) {
 
  732             return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator;
 
  736     auto it = findIterVal(values, values.begin());
 
  737     if (it != values.end()) {
 
  738         auto it2 = findIterVal(values, it + 1);
 
  739         if (it2 == values.cend())
 
  742     if (values.size() == 1)
 
  743         return values.front();
 
  789     struct ArgIteratorInfo {
 
  797     logChecker(
"CheckStl::misMatchingContainers");
 
  809             const Token * 
const ftok = tok;
 
  811             const std::vector<const Token *> args = 
getArguments(ftok);
 
  816             std::map<int, std::vector<ArgIteratorInfo>> containers;
 
  817             for (
int argnr = 1; argnr <= args.size(); ++argnr) {
 
  821                 const Token * 
const argTok = args[argnr - 1];
 
  822                 containers[i->
container].emplace_back(ArgIteratorInfo{argTok, i});
 
  827                 for (
const auto& p : containers)
 
  829                     const std::vector<ArgIteratorInfo>& cargs = p.second;
 
  830                     for (ArgIteratorInfo iter1 : cargs) {
 
  831                         for (ArgIteratorInfo iter2 : cargs) {
 
  832                             if (iter1.tok == iter2.tok)
 
  834                             if (iter1.info->first && iter2.info->last &&
 
  846         if (var && var->isStlStringType() && 
Token::Match(var->nameToken(), 
"%var% (") &&
 
  847             Token::Match(var->nameToken()->tokAt(2), 
"%name% . begin|cbegin|rbegin|crbegin ( ) , %name% . end|cend|rend|crend ( ) ,|)")) {
 
  848             if (var->nameToken()->strAt(2) != var->nameToken()->strAt(8)) {
 
  857     logChecker(
"CheckStl::misMatchingContainerIterator");
 
  870             const std::vector<const Token *> args = 
getArguments(ftok);
 
  874             const Token* iterTok = 
nullptr;
 
  881                 iterTok = args.front();
 
  885                 iterTok = args.front();
 
  914     const Token* ftok = 
nullptr;
 
  921         if (c->unstableErase) {
 
  925         if (c->unstableInsert) {
 
  948     struct InvalidContainerAnalyzer {
 
  955             std::unordered_map<int, Reference> expressions;
 
  957             void add(
const std::vector<Reference>& refs) {
 
  965                 expressions.insert(std::make_pair(r.tok->exprId(), r));
 
  968             std::vector<Reference> invalidTokens()
 const {
 
  969                 std::vector<Reference> result;
 
  970                 std::transform(expressions.cbegin(), expressions.cend(), std::back_inserter(result), 
SelectMapValues{});
 
  974         std::unordered_map<const Function*, Info> invalidMethods;
 
  976         std::vector<Info::Reference> invalidatesContainer(
const Token* tok)
 const {
 
  977             std::vector<Info::Reference> result;
 
  984                 auto it = invalidMethods.find(f);
 
  985                 if (it != invalidMethods.end()) {
 
  986                     std::vector<Info::Reference> refs = it->second.invalidTokens();
 
  987                     std::copy_if(refs.cbegin(), refs.cend(), std::back_inserter(result), [&](
const Info::Reference& r) {
 
  988                         const Variable* var = r.tok->variable();
 
  991                         if (dependsOnThis && !var->isLocal() && !var->isGlobal() && !var->isStatic())
 
  993                         if (!var->isArgument())
 
  995                         if (!var->isReference())
 
 1001                         r.errorPath.push_front(epi);
 
 1003                         const Variable* var = r.tok->variable();
 
 1008                             const Token* tok2 = 
nullptr;
 
 1009                             if (n >= 0 && n < args.size())
 
 1019                     ep.emplace_front(ftok,
 
 1021                                      "', iterators or references to the container's data may be invalid .");
 
 1036                     std::vector<Info::Reference> c = invalidatesContainer(tok);
 
 1039                     invalidMethods[f].add(c);
 
 1066         if (!val.isLocalLifetimeValue())
 
 1071                      val.lifetimeKind)) {
 
 1072             if (val.isInconclusive())
 
 1077                 errorPath->insert(errorPath->end(), val.errorPath.cbegin(), val.errorPath.cend());
 
 1080         if (!val.tokvalue->variable())
 
 1082         if (val.tokvalue->varId() != 
id)
 
 1100         return parent->
next();
 
 1109     InvalidContainerAnalyzer analyzer;
 
 1110     analyzer.analyze(symbolDatabase);
 
 1115                 const Token* blockEnd = blockStart->
link();
 
 1116                 if (contTok->exprId() == 0)
 
 1120                 for (
const Token* tok2 = blockStart; tok2 != blockEnd; tok2 = tok2->
next()) {
 
 1125                         if (r.tok->exprId() != contTok->exprId())
 
 1127                         const Scope* s = tok2->scope();
 
 1143                     std::set<nonneg int> skipVarIds;
 
 1166                         if (skipVarIds.count(info.
tok->
varId()) > 0)
 
 1171                             skipVarIds.insert(info.
tok->
varId());
 
 1176                             bool addressOf = false;
 
 1177                             const Variable* var = ValueFlow::getLifetimeVariable(info.tok, ep, *mSettings, &addressOf);
 
 1179                             if (var && var->declarationId() == r.tok->varId() && !addressOf) {
 
 1181                                 if (var->isArgument() ||
 
 1182                                     (!var->isReference() && !var->isRValueReference() && !isVariableDecl(tok) &&
 
 1183                                      reaches(var->nameToken(), tok, library, &ep))) {
 
 1184                                     errorPath = std::move(ep);
 
 1194                             errorPath = std::move(ep);
 
 1201                     errorPath.insert(errorPath.end(), info.errorPath.cbegin(), info.errorPath.cend());
 
 1202                     errorPath.insert(errorPath.end(), r.errorPath.cbegin(), r.errorPath.cend());
 
 1216     const std::string method = tok ? tok->
str() : 
"erase";
 
 1217     errorPath.emplace_back(loopTok, 
"Iterating container here.");
 
 1221         return epi.first == tok;
 
 1224     const std::string msg = 
"Calling '" + method + 
"' while iterating the container is invalid.";
 
 1225     errorPath.emplace_back(tok, 
"");
 
 1235     errorPath.emplace_back(tok, 
"");
 
 1242     std::string msg = 
"Reference to " + 
name;
 
 1243     errorPath.emplace_back(tok, 
"");
 
 1260         const Token *condition = 
nullptr;
 
 1272         std::vector<const Token *> conds;
 
 1275                       [&](
const Token *cond) {
 
 1279                 conds.emplace_back(cond);
 
 1283         for (
const Token *cond : conds) {
 
 1284             const Token *vartok;
 
 1285             const Token *containerToken;
 
 1292                 containerToken = cond->
next();
 
 1308             const int numId = vartok->
varId();
 
 1311             const int declarationId = containerToken->
varId();
 
 1312             const std::string &containerName = containerToken->
str();
 
 1315                 if (tok3->varId() == declarationId) {
 
 1316                     tok3 = tok3->next();
 
 1322                     else if (
Token::Match(tok3, 
". %name% ( %varid% )", numId)) {
 
 1368     std::ostringstream errmsg;
 
 1371                << 
", otherwise there is negative array index " << index.
intvalue << 
".";
 
 1373         errmsg << 
"Array index " << index.
intvalue << 
" is out of bounds.";
 
 1376     reportError(errorPath, severity, 
"negativeContainerIndex", errmsg.str(), 
CWE786, certainty);
 
 1402     bool inconclusiveType=
false;
 
 1406         if (tok->
str() != 
"(")
 
 1416         int indentlevel = 0U;
 
 1418         for (; tok2 != scope.
bodyEnd; tok2 = tok2->
next()) {
 
 1419             if (tok2->
str() == 
"{") {
 
 1423             if (tok2->
str() == 
"}") {
 
 1424                 if (indentlevel > 0U)
 
 1436             if (indentlevel == 0U && 
Token::Match(tok2, 
"break|return|goto"))
 
 1472                 "Dangerous comparison using operator< on iterator.\n" 
 1473                 "Iterator compared with operator<. This is dangerous since the order of items in the " 
 1474                 "container is not guaranteed. One should use operator!= instead to compare iterators.", 
CWE664, 
Certainty::normal);
 
 1483         if (stdStringLike) {
 
 1491     if (tok->
str() == 
".")
 
 1502     if (!printWarning && !printPerformance)
 
 1517         for (
const Token *tok = conditionStart; tok->
str() != 
"{"; tok = tok->
next()) {
 
 1518             const Token* funcTok = 
nullptr;
 
 1526                 funcTok = tok->
tokAt(2);
 
 1538                 if (tok->
variable()->isArrayOrPointer())
 
 1544                         tok2 = tok2->
next();
 
 1550                         container = 
nullptr;
 
 1562                 else if (printPerformance && container->
stdStringLike && funcTok->
str() == 
"find")
 
 1564             } 
else if (printWarning && 
Token::Match(tok, 
"std :: find|find_if (")) {
 
 1579                     "Inefficient usage of string::find() in condition; string::starts_with() could be faster.\n" 
 1580                     "Either inefficient or wrong usage of string::find(). string::starts_with() will be faster if " 
 1581                     "string::find's result is compared with 0, because it will not scan the whole " 
 1582                     "string. If your intention is to check that there are no findings in the string, " 
 1651     const Token *icontainerTok = 
nullptr;
 
 1652     const Token *ikeyTok = 
nullptr;
 
 1653     const Token *ivalueTok = 
nullptr;
 
 1655         icontainerTok = top->
astOperand1()->astOperand1();
 
 1660         icontainerTok = top->
astOperand1()->astOperand1();
 
 1669     if (!ikeyTok || !icontainerTok)
 
 1671     if (
isSameExpression(
true, containerTok, icontainerTok, settings, 
true, 
false) &&
 
 1697             const Token *containerTok;
 
 1698             const Token *keyTok;
 
 1712                 const Token *valueTok2 =
 
 1728     std::string replaceExpr;
 
 1734         replaceExpr = 
" Instead of '" + tok->
astParent()->expressionString() + 
"' consider using '" +
 
 1735                       tok->
astParent()->astOperand1()->astOperand1()->expressionString() +
 
 1737                       tok->
astParent()->astOperand1()->astOperand2()->expressionString() +
 
 1774                 const Token *varTok = tok;
 
 1775                 if (tok->
strAt(2) != 
"size")
 
 1776                     varTok = varTok->
tokAt(2);
 
 1809     const std::string varname = tok ? tok->
str() : std::string(
"list");
 
 1811                 "$symbol:" + varname + 
"\n" 
 1812                 "Possible inefficient checking for '$symbol' emptiness.\n" 
 1813                 "Checking for '$symbol' emptiness might be inefficient. " 
 1814                 "Using $symbol.empty() instead of $symbol.size() can be faster. " 
 1815                 "$symbol.size() can take linear time but $symbol.empty() is " 
 1833         if (!
Token::Match(tok, 
"%name% . find ( %any% ) != %name% . end|rend|cend|crend ( ) ) { %name% . remove|erase ( %any% ) ;"))
 
 1837         const Token *var1 = tok;
 
 1844         if (var1->
str() == var2->
str() &&
 
 1845             var2->
str() == var3->
str() &&
 
 1846             any1->
str() == any2->
str()) {
 
 1855                 "Redundant checking of STL container element existence before removing it.\n" 
 1856                 "Redundant checking of STL container element existence before removing it. " 
 1874             if (tok2->str() == 
";")
 
 1877             if (!
Token::Match(tok2, 
"%var% = %name% . begin|rbegin|cbegin|crbegin ( ) ; %name% != %name% . end|rend|cend|crend ( ) ; ++| %name% ++| ) {"))
 
 1881             if (tok2->strAt(2) != tok2->strAt(10))
 
 1884             const int iteratorId(tok2->varId());
 
 1887             if (iteratorId == tok2->tokAt(10)->varId())
 
 1891             if (!
Token::Match(tok2->tokAt(16), 
"++ %varid% )", iteratorId) &&
 
 1892                 !
Token::Match(tok2->tokAt(16), 
"%varid% ++ )", iteratorId)) {
 
 1896             const Token *incrementToken = 
nullptr;
 
 1899                 if (tok3->varId() == iteratorId) {
 
 1900                     if (
Token::Match(tok3, 
"%varid% = %name% . insert ( ++| %varid% ++| ,", iteratorId)) {
 
 1906                         incrementToken = tok3;
 
 1914                         incrementToken = 
nullptr;
 
 1915                 } 
else if (tok3->str() == 
"break" || tok3->str() == 
"return")
 
 1916                     incrementToken = 
nullptr;
 
 1926     std::list<const Token*> callstack = { incrementToken1,incrementToken2 };
 
 1928     std::ostringstream errmsg;
 
 1929     errmsg << 
"Missing bounds check for extra iterator increment in loop.\n" 
 1930            << 
"The iterator incrementing is suspicious - it is incremented at line ";
 
 1931     if (incrementToken1)
 
 1932         errmsg << incrementToken1->
linenr();
 
 1933     errmsg << 
" and then at line ";
 
 1934     if (incrementToken2)
 
 1935         errmsg << incrementToken2->
linenr();
 
 1936     errmsg << 
". The loop might unintentionally skip an element in the container. " 
 1937            << 
"There is no comparison between these increments to prevent that the iterator is " 
 1938            << 
"incremented beyond the end.";
 
 1951     const std::set<std::string> stl_string_stream = {
 
 1952         "istringstream", 
"ostringstream", 
"stringstream", 
"wstringstream" 
 1968         std::string argtype;
 
 1970     std::multimap<const Function*, StrArg> c_strFuncParam;
 
 1971     if (printPerformance) {
 
 1978                         c_strFuncParam.emplace(&func, StrArg{ numpar, var.
getTypeName() });
 
 1984     auto isString = [](
const Token* str) -> 
bool {
 
 1986             str = str->astOperand2();
 
 1988             str = str->previous();
 
 1989         return str && ((str->variable() && str->variable()->isStlStringType()) || 
 
 1999         enum {charPtr, stdString, stdStringConstRef, Other} returnType = Other;
 
 2001             returnType = charPtr;
 
 2003             returnType = stdStringConstRef;
 
 2005             returnType = stdString;
 
 2030                 const auto range = c_strFuncParam.equal_range(tok->
function());
 
 2031                 for (std::multimap<const Function*, StrArg>::const_iterator i = range.first; i != range.second; ++i) {
 
 2032                     if (i->second.n == 0)
 
 2037                     for (j = 0; tok2 && j < i->second.n - 1; j++)
 
 2043                     if (!tok2 && j == i->second.n - 1)
 
 2054                             if (ssVar && ssVar->
isStlType(stl_string_stream))
 
 2059             } 
else if (printPerformance && 
Token::Match(tok, 
"%var% (|{ %var% . c_str|data ( ) !!,") &&
 
 2069                 if (isString(str)) {
 
 2070                     const Token* strm = tok;
 
 2079             else if ((returnType == charPtr || (printPerformance && (returnType == stdString || returnType == stdStringConstRef))) && tok->
str() == 
"return") {
 
 2089                     bool is_implicit_std_string = printInconclusive;
 
 2091                     for (
const Token *search_tok = tok2->
next(); search_tok != search_end; search_tok = search_tok->
next()) {
 
 2093                             search_tok->next()->variable() && search_tok->next()->variable()->isStlStringType()) {
 
 2094                             is_implicit_std_string = 
true;
 
 2097                         if (
Token::Match(search_tok, 
"+ std :: string|wstring (")) {
 
 2098                             is_implicit_std_string = 
true;
 
 2103                     if (is_implicit_std_string)
 
 2108                 bool ptrOrRef = 
false;
 
 2110                 const Function* lastFunc = 
nullptr;
 
 2111                 bool funcStr = 
false;
 
 2114                     bool refToNonLocal = 
false;
 
 2117                         refToNonLocal = 
true; 
 
 2121                     ptrOrRef = refToNonLocal || (tok2->
variable() && (tok2->
variable()->isPointer() || tok2->
variable()->isSmartPointer()));
 
 2128                         tok2 = tok2->
tokAt(2);
 
 2132                         funcStr = tok2->
str() == 
"str";
 
 2139                     if ((local || returnType != charPtr) && lastVar && lastVar->
isStlStringType())
 
 2141                     else if (funcStr && lastVar && lastVar->
isStlType(stl_string_stream))
 
 2148                     if (returnType == charPtr)
 
 2160     reportError(tok, 
Severity::error, 
"stlcstrthrow", 
"Dangerous usage of c_str(). The value returned by c_str() is invalid after throwing exception.\n" 
 2161                 "Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid.");
 
 2166     reportError(tok, 
Severity::error, 
"stlcstr", 
"Dangerous usage of c_str(). The value returned by c_str() is invalid after this call.\n" 
 2167                 "Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted.", 
CWE664, 
Certainty::normal);
 
 2173                 "The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string.", 
CWE704, 
Certainty::normal);
 
 2178     std::ostringstream oss;
 
 2179     oss << 
"Passing the result of c_str() to a function that takes " << argtype << 
" as argument no. " << number << 
" is slow and redundant.\n" 
 2180         "The conversion from const char* as returned by c_str() to " << argtype << 
" creates an unnecessary string copy or length calculation. Solve that by directly passing the string.";
 
 2186     std::string msg = 
"Constructing a " + argtype + 
" from the result of c_str() is slow and redundant.\n" 
 2187                       "Constructing a " + argtype + 
" from const char* requires a call to strlen(). Solve that by directly passing the string.";
 
 2193     std::string msg = 
"Assigning the result of c_str() to a " + argtype + 
" is slow and redundant.\n" 
 2194                       "Assigning a const char* to a " + argtype + 
" requires a call to strlen(). Solve that by directly assigning the string.";
 
 2200     std::string msg = 
"Concatenating the result of c_str() and a std::string is slow and redundant.\n" 
 2201                       "Concatenating a const char* with a std::string requires a call to strlen(). Solve that by directly concatenating the strings.";
 
 2207     std::string msg = 
"Passing the result of c_str() to a stream is slow and redundant.\n" 
 2208                       "Passing a const char* to a stream requires a call to strlen(). Solve that by directly passing the string.";
 
 2217     const std::set<std::string> stl_containers_with_empty_and_clear = {
 
 2218         "deque",  
"forward_list",  
"list",
 
 2219         "map",  
"multimap",  
"multiset",  
"set",  
"string",
 
 2220         "unordered_map",  
"unordered_multimap",  
"unordered_multiset",
 
 2221         "unordered_set",  
"vector",  
"wstring" 
 2230     if (!printPerformance && !printWarning)
 
 2238             if (printWarning && 
Token::Match(tok, 
"%var% . compare|find|rfind|find_first_not_of|find_first_of|find_last_not_of|find_last_of ( %name% [,)]") &&
 
 2244             } 
else if (printPerformance && 
Token::Match(tok, 
"%var% . swap ( %name% )") &&
 
 2252                 const std::vector<const Token*> args = 
getArguments(funcTok);
 
 2254                     !args.empty() && args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0) {
 
 2256                 } 
else if (args.empty() || (args[0]->hasKnownIntValue() && args[0]->getKnownIntValue() == 0 &&
 
 2259                 } 
else if (args.size() == 2 && args[1]->hasKnownIntValue() && args[1]->getKnownIntValue() == 0) {
 
 2262             } 
else if (printWarning && 
Token::Match(tok, 
"[{};] %var% . empty ( ) ;") &&
 
 2272                     std::string pattern = 
"%var% = ";
 
 2274                         pattern += t->str();
 
 2277                     pattern += 
"{|( %varid% . begin ( ) ,";
 
 2289     std::ostringstream errmsg;
 
 2290     errmsg << 
"$symbol:" << varname << 
'\n';
 
 2291     errmsg << 
"$symbol:" << 
function << 
'\n';
 
 2292     errmsg << 
"It is inefficient to call '" << varname << 
"." << 
function << 
"(" << varname << 
")' as it always returns 0.\n" 
 2293            << 
"'std::string::" << 
function << 
"()' returns zero when given itself as parameter " 
 2294            << 
"(" << varname << 
"." << 
function << 
"(" << varname << 
")). As it is currently the " 
 2295            << 
"code is inefficient. It is possible either the string searched ('" 
 2296            << varname << 
"') or searched for ('" << varname << 
"') is wrong.";
 
 2303                 "$symbol:" + varname + 
"\n" 
 2304                 "It is inefficient to swap a object with itself by calling '$symbol.swap($symbol)'\n" 
 2305                 "The 'swap()' function has no logical effect when given itself as parameter " 
 2306                 "($symbol.swap($symbol)). As it is currently the " 
 2312     std::string msg = 
"Ineffective call of function 'substr' because ";
 
 2315         msg += 
"it returns an empty string.";
 
 2318         msg += 
"it returns a copy of the object. Use operator= instead.";
 
 2321         msg += 
"a prefix of the string is assigned to itself. Use resize() or pop_back() instead.";
 
 2324         msg += 
"a prefix of the string is assigned to itself. Use replace() instead.";
 
 2332     const std::string msg = 
"Inefficient constructor call: container '" + tok->
str() + 
"' is assigned a partial copy of itself. Use erase() or resize() instead.";
 
 2344                 "$symbol:" + 
function + 
"\n" 
 2345                 "Return value of std::$symbol() ignored. Elements remain in container.\n" 
 2346                 "The return value of std::$symbol() is ignored. This function returns an iterator to the end of the range containing those elements that should be kept. " 
 2347                 "Elements past new end remain valid but with unspecified values. Use the erase method of the container to delete them.", 
CWE762, 
Certainty::normal);
 
 2357     logChecker(
"CheckStl::checkDereferenceInvalidIterator"); 
 
 2366         const Token* startOfCondition = tok->
next();
 
 2368             startOfCondition = startOfCondition->
link()->tokAt(2);
 
 2369         if (!startOfCondition) 
 
 2371         const Token* endOfCondition = startOfCondition->
link();
 
 2372         if (!endOfCondition)
 
 2378             if (!startOfCondition)
 
 2381             if (!endOfCondition)
 
 2387         const bool isOrExpression =
 
 2389         const bool isAndExpression =
 
 2393         const Token* validityCheckTok = 
nullptr;
 
 2394         if (!isOrExpression && isAndExpression) {
 
 2396                 Token::findmatch(startOfCondition, 
"&& %var% != %name% . end|rend|cend|crend ( )", endOfCondition);
 
 2397         } 
else if (isOrExpression && !isAndExpression) {
 
 2399                 Token::findmatch(startOfCondition, 
"%oror% %var% == %name% . end|rend|cend|crend ( )", endOfCondition);
 
 2402         if (!validityCheckTok)
 
 2404         const int iteratorVarId = validityCheckTok->
next()->
varId();
 
 2408         const Token* 
const dereferenceTok =
 
 2409             Token::findmatch(startOfCondition, 
"* %varid%", validityCheckTok, iteratorVarId);
 
 2420     logChecker(
"CheckStl::checkDereferenceInvalidIterator2");
 
 2423         if (
Token::Match(tok, 
"sizeof|decltype|typeid|typeof (")) {
 
 2431         std::vector<ValueFlow::Value> contValues;
 
 2433             if (value.isImpossible())
 
 2435             if (!printInconclusive && value.isInconclusive())
 
 2437             return value.isContainerSizeValue();
 
 2449             bool isInvalidIterator = 
false;
 
 2452                 isInvalidIterator = value.
intvalue > 0;
 
 2454                 isInvalidIterator = 
true;
 
 2456                 auto it = std::find_if(contValues.cbegin(), contValues.cend(), [&](
const ValueFlow::Value& c) {
 
 2457                     if (value.path != c.path)
 
 2459                     if (value.isIteratorStartValue() && value.intvalue >= c.intvalue)
 
 2461                     if (value.isIteratorEndValue() && -value.intvalue > c.intvalue)
 
 2465                 if (it == contValues.end())
 
 2469                     isInvalidIterator = 
true;
 
 2472             bool unknown = 
false;
 
 2473             const Token* emptyAdvance = 
nullptr;
 
 2474             const Token* advanceIndex = 
nullptr;
 
 2475             if (cValue && cValue->
intvalue == 0) {
 
 2516     if (!tok || !value) {
 
 2529         std::string errmsg = std::string(value->
isKnown() ? 
"Dereference" : 
"Possible dereference") + 
" of an invalid iterator";
 
 2530         if (!varname.empty())
 
 2531             errmsg = 
"$symbol:" + varname + 
'\n' + errmsg + 
": $symbol";
 
 2535                     "derefInvalidIterator",
 
 2544                 "derefInvalidIterator",
 
 2545                 "$symbol:" + iterName + 
"\n" 
 2546                 "Possible dereference of an invalid iterator: $symbol\n" 
 2547                 "Possible dereference of an invalid iterator: $symbol. Make sure to check that the iterator is valid before dereferencing it - not after.", 
CWE825, 
Certainty::normal);
 
 2558     if (start->
str() != 
"{")
 
 2567     if (endStatement->
next() != endToken)
 
 2574     if (start->
str() != 
"{")
 
 2580     if (endStatement->
next() != endToken)
 
 2582     return endStatement;
 
 2604     if (start->
str() != 
"{")
 
 2612     if (endStatement->
next() != endToken)
 
 2626     if (start->
str() != 
"{")
 
 2628     const Token *varTok = 
nullptr;
 
 2630         varTok = start->
tokAt(2);
 
 2632         varTok = start->
tokAt(1);
 
 2635     input = varTok->
varId() == varid;
 
 2641     if (start->
str() != 
"{")
 
 2649     const Token *endBodyTok = bodyTok->
link();
 
 2652     if (endBodyTok->
next() != endToken)
 
 2682     if (
Token::Match(tok, 
"= %varid% %oror%|%or%|&&|& %bool% ;", varid) &&
 
 2695     if (
Token::Match(tok, 
"= %varid% %oror%|%or%|&&|&", varid)) {
 
 2715     if (algo == 
"std::max_element")
 
 2716         return "std::min_element";
 
 2717     if (algo == 
"std::min_element")
 
 2718         return "std::max_element";
 
 2725         return "std::accumulate";
 
 2726     if (!
hasVarIds(condTok, loopVar, assignVar))
 
 2727         return "std::accumulate";
 
 2728     std::string algo = 
"std::max_element";
 
 2730         algo = 
"std::min_element";
 
 2739     struct LoopAnalyzer {
 
 2740         const Token* bodyTok = 
nullptr;
 
 2741         const Token* loopVar = 
nullptr;
 
 2742         const Settings* settings = 
nullptr;
 
 2743         std::set<nonneg int> varsChanged;
 
 2745         explicit LoopAnalyzer(
const Token* tok, 
const Settings* psettings)
 
 2746             : bodyTok(tok->next()->link()->next()), settings(psettings)
 
 2753                 findChangedVariables();
 
 2756         bool isLoopVarChanged()
 const {
 
 2757             return varsChanged.count(loopVar->
varId()) > 0;
 
 2760         bool isModified(
const Token* tok)
 const 
 2765             for (
int i = 0; i < n; i++) {
 
 2777         template<
class Predicate, 
class F>
 
 2786         template<
class Predicate>
 
 2796         bool hasGotoOrBreak()
 const 
 2803         bool valid()
 const {
 
 2804             return bodyTok && loopVar;
 
 2807         std::string findAlgo()
 const 
 2811             bool loopVarChanged = isLoopVarChanged();
 
 2812             if (!loopVarChanged && varsChanged.empty()) {
 
 2813                 if (hasGotoOrBreak())
 
 2815                 bool alwaysTrue = 
true;
 
 2816                 bool alwaysFalse = 
true;
 
 2817                 auto hasReturn = [](
const Token* tok) {
 
 2824                         alwaysFalse = 
false;
 
 2827                     (returnTok->
values().front().intvalue ? alwaysTrue : alwaysFalse) &= 
true;
 
 2828                     (returnTok->
values().front().intvalue ? alwaysFalse : alwaysTrue) &= 
false;
 
 2830                 if (alwaysTrue == alwaysFalse)
 
 2833                     return "std::any_of";
 
 2834                 return "std::all_of or std::none_of";
 
 2839         bool isLocalVar(
const Variable* var)
 const 
 2852         void findChangedVariables()
 
 2854             std::set<nonneg int> vars;
 
 2856                 if (tok->
varId() == 0)
 
 2858                 if (vars.count(tok->
varId()) > 0)
 
 2861                     vars.insert(tok->
varId());
 
 2864                 if (!isModified(tok))
 
 2866                 varsChanged.insert(tok->
varId());
 
 2867                 vars.insert(tok->
varId());
 
 2880     auto checkAssignee = [](
const Token* tok) {
 
 2886     auto isConditionWithoutSideEffects = [
this](
const Token* tok) -> 
bool {
 
 2893         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
 2900             std::string algoName = a.findAlgo();
 
 2901             if (!algoName.empty()) {
 
 2908             const Token* loopVar{};
 
 2909             bool isIteratorLoop = 
false;
 
 2912                 if (loopVar->
varId() == 0)
 
 2921                 if (!initTok || !condTok || !stepTok)
 
 2930                 isIteratorLoop = 
true;
 
 2934             bool useLoopVarInAssign{}, hasBreak{};
 
 2939                 const int assignVarId = assignTok->
astOperand1()->varId();
 
 2941                 if (assignVarId == loopVar->
varId()) {
 
 2942                     if (useLoopVarInAssign)
 
 2943                         algo = 
"std::transform";
 
 2947                         algo = 
"std::generate";
 
 2949                         algo = 
"std::fill or std::generate";
 
 2951                     if (
addByOne(assignTok, assignVarId))
 
 2952                         algo = 
"std::distance";
 
 2954                         algo = 
"std::any_of, std::all_of, std::none_of, or std::accumulate";
 
 2958                         algo = 
"std::accumulate";
 
 2964             bool useLoopVarInMemCall;
 
 2966             if (memberAccessTok && !isIteratorLoop) {
 
 2968                 const int contVarId = memberAccessTok->
astOperand1()->varId();
 
 2969                 if (contVarId == loopVar->
varId())
 
 2971                 if (memberCallTok->
str() == 
"push_back" ||
 
 2972                     memberCallTok->
str() == 
"push_front" ||
 
 2973                     memberCallTok->
str() == 
"emplace_back") {
 
 2975                     if (useLoopVarInMemCall)
 
 2978                         algo = 
"std::transform";
 
 2985             bool useLoopVarInIncrement;
 
 2989                 if (useLoopVarInIncrement)
 
 2990                     algo = 
"std::transform";
 
 2992                     algo = 
"std::distance";
 
 3005                     const int assignVarId = assignTok->
astOperand1()->varId();
 
 3007                     if (assignVarId == loopVar->
varId()) {
 
 3008                         if (useLoopVarInAssign)
 
 3009                             algo = 
"std::transform";
 
 3011                             algo = 
"std::replace_if";
 
 3013                         if (
addByOne(assignTok, assignVarId))
 
 3014                             algo = 
"std::count_if";
 
 3016                             algo = 
"std::any_of, std::all_of, std::none_of, or std::accumulate";
 
 3017                         else if (assignTok->
str() != 
"=")
 
 3018                             algo = 
"std::accumulate";
 
 3019                         else if (hasBreak && isConditionWithoutSideEffects(condBodyTok))
 
 3020                             algo = 
"std::any_of, std::all_of, std::none_of";
 
 3030                 if (memberAccessTok) {
 
 3032                     const int contVarId = memberAccessTok->
astOperand1()->varId();
 
 3033                     if (contVarId == loopVar->
varId())
 
 3035                     if (memberCallTok->
str() == 
"push_back" ||
 
 3036                         memberCallTok->
str() == 
"push_front" ||
 
 3037                         memberCallTok->
str() == 
"emplace_back") {
 
 3038                         if (useLoopVarInMemCall)
 
 3049                     if (useLoopVarInIncrement)
 
 3050                         algo = 
"std::transform";
 
 3052                         algo = 
"std::count_if";
 
 3063                         algo = 
"std::find_if";
 
 3065                         algo = 
"std::any_of";
 
 3076     const std::string var = tok ? tok->
expressionString() : std::string(
"var");
 
 3080         msg = 
"Using " + algo + 
" with iterator '" + var + 
"' that is always empty.";
 
 3082         msg = 
"Iterating over container '" + var + 
"' that is always empty.";
 
 3086                 "knownEmptyContainer",
 
 3097         if (!v.isContainerSizeValue())
 
 3099         if (v.intvalue != 0)
 
 3111         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
 3117             if (tok->
str() == 
"for") {
 
 3128                 const std::vector<const Token *> args = 
getArguments(tok);
 
 3132                 for (
int argnr = 1; argnr <= args.size(); ++argnr) {
 
 3136                     const Token * 
const argTok = args[argnr - 1];
 
 3150     if (!ftok || !itertok || !val) {
 
 3154                     "Either the condition 'x' is redundant or function 'erase()' is called on the iterator 'iter' which is out of bounds.", 
CWE628, 
Certainty::normal);
 
 3157     const std::string& func = ftok->
str();
 
 3160     const bool isConditional = val->
isPossible();
 
 3162     if (isConditional) {
 
 3165         msg = 
"Calling function '" + func + 
"()' on the iterator '" + iter + 
"' which is out of bounds.";
 
 3169     const std::string 
id = isConditional ? 
"eraseIteratorOutOfBoundsCond" : 
"eraseIteratorOutOfBounds";
 
 3178         if (v.isPossible() || v.isKnown()) {
 
 3179             switch (v.valueType) {
 
 3180             case ValueFlow::Value::ValueType::ITERATOR_END:
 
 3181                 return v.intvalue >= 0;
 
 3182             case ValueFlow::Value::ValueType::ITERATOR_START:
 
 3183                 return (v.intvalue < 0) || (sizeVal && v.intvalue >= sizeVal->intvalue);
 
 3190     return it != tok->
values().end() ? &*it : 
nullptr;
 
 3195     logChecker(
"CheckStl::eraseIteratorOutOfBounds");
 
 3197         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
 3208             const std::vector<const Token*> args = 
getArguments(ftok);
 
 3209             if (args.size() != 1) 
 
 3222     return Token::Match(tok, 
"std :: mutex|recursive_mutex|timed_mutex|recursive_timed_mutex|shared_mutex");
 
 3228     return Token::Match(tok, 
"std :: lock_guard|unique_lock|scoped_lock|shared_lock");
 
 3244                 "Lock guard is defined globally. Lock guards are intended to be local. A global lock guard could lead to a deadlock since it won't unlock until the end of the program.", 
CWE833, 
Certainty::normal);
 
 3251                 "The lock is ineffective because the mutex is locked at the same scope as the mutex itself.", 
CWE667, 
Certainty::normal);
 
 3260         std::set<nonneg int> checkedVars;
 
 3261         for (
const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->
next()) {
 
 3274             } 
else if (
Token::Match(tok, 
"%var% (|{ %var% )|}|,")) {
 
bool astIsContainer(const Token *tok)
 
const Token * getIteratorExpression(const Token *tok)
 
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
 
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
 
bool astIsIntegral(const Token *tok, bool unknown)
Is expression of integral type?
 
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
 
bool isTemporary(const Token *tok, const Library *library, bool unknown)
 
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
 
bool astIsPointer(const Token *tok)
 
bool isStlStringType(const Token *tok)
 
bool astIsContainerOwned(const Token *tok)
 
bool astIsLHS(const Token *tok)
 
bool astIsBool(const Token *tok)
Is expression of boolean type?
 
bool isVariableDecl(const Token *tok)
 
static int getArgumentPos(const Token *ftok, const Token *tokToFind)
 
Token * getInitTok(Token *tok)
 
const Token * astParentSkipParens(const Token *tok)
 
Token * getCondTok(Token *tok)
 
bool astIsRHS(const Token *tok)
 
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
 
const Token * nextAfterAstRightmostLeaf(const Token *tok)
 
Token * getStepTok(Token *tok)
 
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
Is variable changed by function call? In case the answer of the question is inconclusive,...
 
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
 
bool astIsIterator(const Token *tok)
 
bool isConstExpression(const Token *tok, const Library &library)
 
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
 
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
 
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
 
static std::string flipMinMax(const std::string &algo)
 
static const CWE CWE788(788U)
 
static const Token * getContainerIndex(const Library::Container *container, const Token *parent)
 
static bool isElementAccessYield(Library::Container::Yield yield)
 
static const CWE CWE398(398U)
 
static const CWE CWE762(762U)
 
static bool accumulateBool(const Token *tok, nonneg int varid)
 
static const Token * singleConditionalInScope(const Token *start, nonneg int varid, const Settings &settings)
 
static bool isVector(const Token *tok)
 
static const Token * singleIncrementInScope(const Token *start, nonneg int varid, bool &input)
 
static bool containerAppendsElement(const Library::Container *container, const Token *parent)
 
static const Token * singleMemberCallInScope(const Token *start, nonneg int varid, bool &input, const Settings &settings)
 
static bool isKnownEmptyContainer(const Token *tok)
 
static std::vector< const Token * > getAddressContainer(const Token *tok)
 
static const CWE CWE704(704U)
 
static const CWE CWE597(597U)
 
static bool isLocalMutex(const Variable *var, const Scope *scope)
 
static bool containerYieldsElement(const Library::Container *container, const Token *parent)
 
static const Token * getInvalidMethod(const Token *tok)
 
static const CWE CWE825(825U)
 
static const Token * getContainerFromSize(const Library::Container *container, const Token *tok)
 
static bool isLocal(const Token *tok)
 
static const Token * endOfExpression(const Token *tok)
 
static const Token * singleStatement(const Token *start)
 
static bool isEarlyExit(const Token *start)
 
static const CWE CWE833(833U)
 
static bool containerPopsElement(const Library::Container *container, const Token *parent)
 
static const Token * skipLocalVars(const Token *const tok)
 
static const CWE CWE667(667U)
 
static std::pair< const Token *, const Token * > isMapFind(const Token *tok)
 
static bool isCpp03ContainerSizeSlow(const Token *tok)
Is container.size() slow?
 
static const Token * findInsertValue(const Token *tok, const Token *containerTok, const Token *keyTok, const Settings &settings)
 
static std::string indexValueString(const ValueFlow::Value &indexValue, const std::string &containerName=emptyString)
 
static const CWE CWE786(786U)
 
static std::string minmaxCompare(const Token *condTok, nonneg int loopVar, nonneg int assignVar, bool invert=false)
 
static const CWE CWE834(834U)
 
static bool hasVarIds(const Token *tok, nonneg int var1, nonneg int var2)
 
static bool isLockGuard(const Variable *var)
 
static bool isSameIteratorContainerExpression(const Token *tok1, const Token *tok2, const Settings &settings, ValueFlow::Value::LifetimeKind kind=ValueFlow::Value::LifetimeKind::Iterator)
 
static bool accumulateBoolLiteral(const Token *tok, nonneg int varid)
 
static const Token * getLoopContainer(const Token *tok)
 
static const ValueFlow::Value * getOOBIterValue(const Token *tok, const ValueFlow::Value *sizeVal)
 
static std::string getContainerName(const Token *containerToken)
 
static bool addByOne(const Token *tok, nonneg int varid)
 
static bool isMutex(const Variable *var)
 
static const CWE CWE664(664U)
 
static const Token * singleAssignInScope(const Token *start, nonneg int varid, bool &input, bool &hasBreak, const Settings &settings)
 
static const CWE CWE628(628U)
 
static bool if_findCompare(const Token *const tokBack, bool stdStringLike)
 
static const Token * skipMembers(const Token *tok)
 
static const ValueFlow::Value * getInnerLifetime(const Token *tok, nonneg int id, ErrorPath *errorPath=nullptr, int depth=4)
 
static bool isIterator(const Variable *var, bool &inconclusiveType)
 
static ValueFlow::Value getLifetimeIteratorValue(const Token *tok, MathLib::bigint path=0)
 
bool isPointerDeRef(const Token *tok, bool &unknown) const
Is there a pointer dereference? Everything that should result in a nullpointer dereference error mess...
 
Check STL usage (invalidation of iterators, mismatching containers, etc)
 
void outOfBoundsIndexExpression()
Accessing container out of bounds, following index expression.
 
void missingComparison()
Missing inner comparison, when incrementing iterator inside loop Dangers:
 
void erase()
Dangerous usage of erase.
 
void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2)
 
void sizeError(const Token *tok)
 
void uselessCalls()
Check calls that using them is useless
 
void checkDereferenceInvalidIterator2()
 
void stlBoundariesError(const Token *tok)
 
void uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
 
void invalidContainerError(const Token *tok, const Token *contTok, const ValueFlow::Value *val, ErrorPath errorPath)
 
void mismatchingContainerIteratorError(const Token *containerTok, const Token *iterTok, const Token *containerTok2)
 
void uselessCallsSwapError(const Token *tok, const std::string &varname)
 
void knownEmptyContainerError(const Token *tok, const std::string &algo)
 
void size()
Suggest using empty() instead of checking size() against zero for containers.
 
void mismatchingContainersError(const Token *tok1, const Token *tok2)
 
void eraseIteratorOutOfBoundsError(const Token *ftok, const Token *itertok, const ValueFlow::Value *val=nullptr)
 
void string_c_strStream(const Token *tok)
 
void uselessCallsRemoveError(const Token *tok, const std::string &function)
 
void uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function)
 
void sameIteratorExpressionError(const Token *tok)
 
bool isContainerSize(const Token *containerToken, const Token *expr) const
 
void stlOutOfBounds()
Finds errors like this: for (unsigned ii = 0; ii <= foo.size(); ++ii)
 
void string_c_strParam(const Token *tok, nonneg int number, const std::string &argtype="std::string")
 
void dereferenceInvalidIteratorError(const Token *deref, const std::string &iterName)
 
void invalidIteratorError(const Token *tok, const std::string &iteratorName)
 
void negativeIndexError(const Token *tok, const ValueFlow::Value &index)
 
void outOfBounds()
Accessing container out of bounds using ValueFlow.
 
void mismatchingContainerIterator()
 
void negativeIndex()
negative index for array like containers
 
void dereferenceErasedError(const Token *erased, const Token *deref, const std::string &itername, bool inconclusive)
Dereferencing an erased iterator.
 
void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2)
 
void if_find()
if (a.find(x)) - possibly incorrect condition
 
void stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at)
 
void checkFindInsertError(const Token *tok)
 
void useStlAlgorithm()
Look for loops that can replaced with std algorithms.
 
void invalidContainerReferenceError(const Token *tok, const Token *contTok, ErrorPath errorPath)
 
void iterators()
Finds errors like this: for (it = foo.begin(); it != bar.end(); ++it)
 
void string_c_strThrowError(const Token *tok)
 
void useStlAlgorithmError(const Token *tok, const std::string &algoName)
 
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
 
void stlBoundaries()
bad condition.
 
void string_c_str()
Check for common mistakes when using the function string::c_str()
 
void mismatchingContainers()
Mismatching containers: std::find(foo.begin(), bar.end(), x)
 
void knownEmptyContainer()
 
void string_c_strConcat(const Token *tok)
 
bool isContainerSizeGE(const Token *containerToken, const Token *expr) const
 
void globalLockGuardError(const Token *tok)
 
void checkDereferenceInvalidIterator()
Check for dereferencing an iterator that is invalid
 
void iteratorsError(const Token *tok, const std::string &containerName1, const std::string &containerName2)
 
void redundantCondition()
Check for redundant condition 'if (ints.find(1) != ints.end()) ints.remove(123);'.
 
void localMutexError(const Token *tok)
 
void eraseCheckLoopVar(const Scope &scope, const Variable *var)
 
void redundantIfRemoveError(const Token *tok)
 
void eraseIteratorOutOfBounds()
 
void uselessCallsConstructorError(const Token *tok)
 
void string_c_strError(const Token *tok)
 
void string_c_strAssignment(const Token *tok, const std::string &argtype="std::string")
 
void string_c_strConstructor(const Token *tok, const std::string &argtype="std::string")
 
bool checkIteratorPair(const Token *tok1, const Token *tok2)
 
void if_findError(const Token *tok, bool str)
 
void string_c_strReturn(const Token *tok)
 
void invalidContainerLoopError(const Token *tok, const Token *loopTok, ErrorPath errorPath)
 
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index)
 
void uselessCallsEmptyError(const Token *tok)
 
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 std::string & name() const
class name, used to generate documentation
 
nonneg int argCount() const
 
const Token * tokenDef
function name token in class definition
 
std::list< Variable > argumentList
argument list, must remain list due to clangimport usage!
 
Action getAction(const std::string &function) const
 
Yield getYield(const std::string &function) const
 
Library definitions handling.
 
const Container * detectIterator(const Token *typeStart) const
 
const ArgumentChecks::IteratorInfo * getArgIteratorInfo(const Token *ftok, int argnr) const
 
const Container * detectContainer(const Token *typeStart) const
 
std::list< Function > functionList
 
bool isNestedIn(const Scope *outer) const
 
Function * function
function info for this function
 
const Token * classDef
class/struct/union/namespace token
 
const Token * bodyStart
'{' token
 
const Token * bodyEnd
'}' token
 
bool isExecutable() const
 
This is just a container for general settings so that we don't need to pass individual values to func...
 
bool isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck=false) const
Returns true if given value can be shown.
 
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
 
SimpleEnableGroup< Certainty > certainty
 
SimpleEnableGroup< Severity > severity
 
Standards standards
Struct contains standards settings.
 
bool isEnabled(T flag) const
 
const std::vector< const Variable * > & variableList() 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.
 
bool hasKnownValue() const
 
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.
 
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
 
bool hasKnownIntValue() const
 
MathLib::bigint getKnownIntValue() const
 
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
 
const Token * nextTemplateArgument() const
 
bool isArithmeticalOp() const
 
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) 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
 
const ValueFlow::Value * getValueGE(const MathLib::bigint val, const Settings &settings) const
 
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
 
const Token * tokAt(int index) const
 
Token::Type tokType() 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
 
bool isAssignmentOp() 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
 
const Token * nextArgument() 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
 
const Function * getFunction(const std::string &funcName) const
 
bool isSymbolicValue() const
 
Bound bound
The value bound
 
MathLib::bigint path
Path id.
 
bool isIteratorValue() const
 
bool errorSeverity() const
 
bool isLifetimeValue() const
 
bool isImpossible() const
 
const Token * condition
Condition that this value depends on.
 
const Token * tokvalue
token value - the token that has the value.
 
long long intvalue
int value (or sometimes bool value?)
 
enum ValueFlow::Value::LifetimeKind lifetimeKind
 
bool isIteratorStartValue() const
 
bool isIteratorEndValue() const
 
bool isInconclusive() const
 
enum ValueType::Type type
 
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
 
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
 
Information about a member variable.
 
bool isArgument() const
Is variable a function argument.
 
bool isReference() const
Is reference variable.
 
bool isStlStringViewType() const
 
std::string getTypeName() const
 
bool isRValueReference() const
Is reference variable.
 
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
 
bool isLocal() const
Is variable local.
 
const Type * type() const
Get Type pointer of known type.
 
const Scope * scope() const
Get Scope pointer of enclosing scope.
 
bool isGlobal() const
Is variable global.
 
const Token * typeEndToken() const
Get type end token.
 
bool isConst() const
Is variable const.
 
const Token * nameToken() const
Get name token.
 
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
 
const Token * typeStartToken() const
Get type start token.
 
bool isPointer() const
Is pointer variable.
 
bool isStlStringType() const
Checks if the variable is an STL type ('std::') E.g.
 
bool isStatic() const
Is variable static.
 
static const std::string emptyString
 
T * findToken(T *start, const Token *end, const Predicate &pred)
 
std::vector< T * > findTokens(T *start, const Token *end, const Predicate &pred)
 
Severity
enum class for severity.
 
std::pair< const Token *, std::string > ErrorPathItem
 
const Library::Container * getLibraryContainer(const Token *tok)
 
std::list< ErrorPathItem > ErrorPath
 
@ performance
Performance warning.
 
@ error
Programming error.
 
std::string eitherTheConditionIsRedundant(const Token *condition)
 
const Value * findValue(const std::list< Value > &values, const Settings &settings, const std::function< bool(const Value &)> &pred)
 
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath)
 
std::vector< Value > isOutOfBounds(const Value &size, const Token *indexTok, bool possible=true)
 
CPPCHECKLIB std::vector< Value > getLifetimeObjValues(const Token *tok, bool inconclusive=false, MathLib::bigint path=0)
 
static const Token * assignExpr(const Token *tok)
 
bool reaches(const Token *start, const Token *dest, const Library &library, ErrorPath *errorPath)
Returns true if there is a path between the two tokens.
 
enum Standards::cppstd_t cpp
 
bool contains(const Range &r, const T &x)