Check for iterators being dereferenced before being checked for validity. E.g. if (*i && i != str.end()) { }
| 2415 | // Check for iterators being dereferenced before being checked for validity. |
| 2416 | // E.g. if (*i && i != str.end()) { } |
| 2417 | void CheckStlImpl::checkDereferenceInvalidIterator() |
| 2418 | { |
| 2419 | if (!mSettings.severity.isEnabled(Severity::warning)) |
| 2420 | return; |
| 2421 | |
| 2422 | logChecker("CheckStl::checkDereferenceInvalidIterator"); // warning |
| 2423 | |
| 2424 | // Iterate over "if", "while", and "for" conditions where there may |
| 2425 | // be an iterator that is dereferenced before being checked for validity. |
| 2426 | for (const Scope &scope : mTokenizer->getSymbolDatabase()->scopeList) { |
| 2427 | if (!(scope.type == ScopeType::eIf || scope.isLoopScope())) |
| 2428 | continue; |
| 2429 | |
| 2430 | const Token* const tok = scope.classDef; |
| 2431 | const Token* startOfCondition = tok->next(); |
| 2432 | if (scope.type == ScopeType::eDo) |
| 2433 | startOfCondition = startOfCondition->link()->tokAt(2); |
| 2434 | if (!startOfCondition) // ticket #6626 invalid code |
| 2435 | continue; |
| 2436 | const Token* endOfCondition = startOfCondition->link(); |
| 2437 | if (!endOfCondition) |
| 2438 | continue; |
| 2439 | |
| 2440 | // For "for" loops, only search between the two semicolons |
| 2441 | if (scope.type == ScopeType::eFor) { |
| 2442 | startOfCondition = Token::findsimplematch(tok->tokAt(2), ";", endOfCondition); |
| 2443 | if (!startOfCondition) |
| 2444 | continue; |
| 2445 | endOfCondition = Token::findsimplematch(startOfCondition->next(), ";", endOfCondition); |
| 2446 | if (!endOfCondition) |
| 2447 | continue; |
| 2448 | } |
| 2449 | |
| 2450 | // Only consider conditions composed of all "&&" terms and |
| 2451 | // conditions composed of all "||" terms |
| 2452 | const bool isOrExpression = |
| 2453 | Token::findsimplematch(startOfCondition, "||", endOfCondition) != nullptr; |
| 2454 | const bool isAndExpression = |
| 2455 | Token::findsimplematch(startOfCondition, "&&", endOfCondition) != nullptr; |
| 2456 | |
| 2457 | // Look for a check of the validity of an iterator |
| 2458 | const Token* validityCheckTok = nullptr; |
| 2459 | if (!isOrExpression && isAndExpression) { |
| 2460 | validityCheckTok = |
| 2461 | Token::findmatch(startOfCondition, "&& %var% != %name% . end|rend|cend|crend ( )", endOfCondition); |
| 2462 | } else if (isOrExpression && !isAndExpression) { |
| 2463 | validityCheckTok = |
| 2464 | Token::findmatch(startOfCondition, "%oror% %var% == %name% . end|rend|cend|crend ( )", endOfCondition); |
| 2465 | } |
| 2466 | |
| 2467 | if (!validityCheckTok) |
| 2468 | continue; |
| 2469 | const int iteratorVarId = validityCheckTok->next()->varId(); |
| 2470 | |
| 2471 | // If the iterator dereference is to the left of the check for |
| 2472 | // the iterator's validity, report an error. |
| 2473 | const Token* const dereferenceTok = |
| 2474 | Token::findmatch(startOfCondition, "* %varid%", validityCheckTok, iteratorVarId); |
no test coverage detected