LCOV - code coverage report
Current view: top level - lib - checkother.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 2482 2582 96.1 %
Date: 2024-04-28 12:00:40 Functions: 139 139 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2024 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : 
      20             : //---------------------------------------------------------------------------
      21             : #include "checkother.h"
      22             : 
      23             : #include "astutils.h"
      24             : #include "fwdanalysis.h"
      25             : #include "library.h"
      26             : #include "mathlib.h"
      27             : #include "platform.h"
      28             : #include "settings.h"
      29             : #include "standards.h"
      30             : #include "symboldatabase.h"
      31             : #include "token.h"
      32             : #include "tokenize.h"
      33             : #include "tokenlist.h"
      34             : #include "utils.h"
      35             : #include "valueflow.h"
      36             : #include "vfvalue.h"
      37             : 
      38             : #include <algorithm> // find_if()
      39             : #include <cctype>
      40             : #include <list>
      41             : #include <map>
      42             : #include <set>
      43             : #include <sstream>
      44             : #include <utility>
      45             : 
      46             : //---------------------------------------------------------------------------
      47             : 
      48             : // Register this check class (by creating a static instance of it)
      49             : namespace {
      50             :     CheckOther instance;
      51             : }
      52             : 
      53             : static const CWE CWE128(128U);   // Wrap-around Error
      54             : static const CWE CWE131(131U);   // Incorrect Calculation of Buffer Size
      55             : static const CWE CWE197(197U);   // Numeric Truncation Error
      56             : static const CWE CWE362(362U);   // Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
      57             : static const CWE CWE369(369U);   // Divide By Zero
      58             : static const CWE CWE398(398U);   // Indicator of Poor Code Quality
      59             : static const CWE CWE475(475U);   // Undefined Behavior for Input to API
      60             : static const CWE CWE561(561U);   // Dead Code
      61             : static const CWE CWE563(563U);   // Assignment to Variable without Use ('Unused Variable')
      62             : static const CWE CWE570(570U);   // Expression is Always False
      63             : static const CWE CWE571(571U);   // Expression is Always True
      64             : static const CWE CWE672(672U);   // Operation on a Resource after Expiration or Release
      65             : static const CWE CWE628(628U);   // Function Call with Incorrectly Specified Arguments
      66             : static const CWE CWE683(683U);   // Function Call With Incorrect Order of Arguments
      67             : static const CWE CWE704(704U);   // Incorrect Type Conversion or Cast
      68             : static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
      69             : static const CWE CWE768(768U);   // Incorrect Short Circuit Evaluation
      70             : static const CWE CWE783(783U);   // Operator Precedence Logic Error
      71             : 
      72             : //----------------------------------------------------------------------------------
      73             : // The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value.
      74             : // If this return value is stored in a character variable and then compared
      75             : // to EOF, which is an integer, the comparison maybe be false.
      76             : //
      77             : // Reference:
      78             : // - Ticket #160
      79             : // - http://www.cplusplus.com/reference/cstdio/fgetc/
      80             : // - http://www.cplusplus.com/reference/cstdio/getc/
      81             : // - http://www.cplusplus.com/reference/cstdio/getchar/
      82             : // - http://www.cplusplus.com/reference/cstdio/ungetc/ ...
      83             : //----------------------------------------------------------------------------------
      84        3807 : void CheckOther::checkCastIntToCharAndBack()
      85             : {
      86        3807 :     if (!mSettings->severity.isEnabled(Severity::warning))
      87        2322 :         return;
      88             : 
      89        1485 :     logChecker("CheckOther::checkCastIntToCharAndBack"); // warning
      90             : 
      91        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
      92        8648 :     for (const Scope * scope : symbolDatabase->functionScopes) {
      93       14326 :         std::map<int, std::string> vars;
      94      234503 :         for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
      95             :             // Quick check to see if any of the matches below have any chances
      96      227340 :             if (!Token::Match(tok, "%var%|EOF %comp%|="))
      97      224003 :                 continue;
      98        3337 :             if (Token::Match(tok, "%var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (")) {
      99          18 :                 const Variable *var = tok->variable();
     100          18 :                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
     101           9 :                     vars[tok->varId()] = tok->strAt(2);
     102             :                 }
     103        3319 :             } else if (Token::Match(tok, "EOF %comp% ( %var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (")) {
     104           1 :                 tok = tok->tokAt(3);
     105           1 :                 const Variable *var = tok->variable();
     106           1 :                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
     107           1 :                     checkCastIntToCharAndBackError(tok, tok->strAt(2));
     108             :                 }
     109        3318 :             } else if (tok->isCpp() && (Token::Match(tok, "EOF %comp% ( %var% = std :: cin . get (") || Token::Match(tok, "EOF %comp% ( %var% = cin . get ("))) {
     110           0 :                 tok = tok->tokAt(3);
     111           0 :                 const Variable *var = tok->variable();
     112           0 :                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
     113           0 :                     checkCastIntToCharAndBackError(tok, "cin.get");
     114             :                 }
     115        3318 :             } else if (tok->isCpp() && (Token::Match(tok, "%var% = std :: cin . get (") || Token::Match(tok, "%var% = cin . get ("))) {
     116           8 :                 const Variable *var = tok->variable();
     117           8 :                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
     118           4 :                     vars[tok->varId()] = "cin.get";
     119             :                 }
     120        3310 :             } else if (Token::Match(tok, "%var% %comp% EOF")) {
     121           8 :                 if (vars.find(tok->varId()) != vars.end()) {
     122           4 :                     checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
     123             :                 }
     124        3302 :             } else if (Token::Match(tok, "EOF %comp% %var%")) {
     125          10 :                 tok = tok->tokAt(2);
     126          10 :                 if (vars.find(tok->varId()) != vars.end()) {
     127           5 :                     checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
     128             :                 }
     129             :             }
     130             :         }
     131             :     }
     132             : }
     133             : 
     134          14 : void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName)
     135             : {
     136          14 :     reportError(
     137             :         tok,
     138             :         Severity::warning,
     139             :         "checkCastIntToCharAndBack",
     140          28 :         "$symbol:" + strFunctionName + "\n"
     141             :         "Storing $symbol() return value in char variable and then comparing with EOF.\n"
     142             :         "When saving $symbol() return value in char variable there is loss of precision. "
     143             :         " When $symbol() returns EOF this value is truncated. Comparing the char "
     144             :         "variable with EOF can have unexpected results. For instance a loop \"while (EOF != (c = $symbol());\" "
     145             :         "loops forever on some compilers/platforms and on other compilers/platforms it will stop "
     146          14 :         "when the file contains a matching character.", CWE197, Certainty::normal
     147          28 :         );
     148          14 : }
     149             : 
     150             : 
     151             : //---------------------------------------------------------------------------
     152             : // Clarify calculation precedence for ternary operators.
     153             : //---------------------------------------------------------------------------
     154        3807 : void CheckOther::clarifyCalculation()
     155             : {
     156        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCalculation"))
     157        2321 :         return;
     158             : 
     159        1486 :     logChecker("CheckOther::clarifyCalculation"); // style
     160             : 
     161        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     162        8649 :     for (const Scope * scope : symbolDatabase->functionScopes) {
     163      234526 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
     164             :             // ? operator where lhs is arithmetical expression
     165      227363 :             if (tok->str() != "?" || !tok->astOperand1() || !tok->astOperand1()->isCalculation())
     166      227315 :                 continue;
     167          48 :             if (!tok->astOperand1()->isArithmeticalOp() && tok->astOperand1()->tokType() != Token::eBitOp)
     168          34 :                 continue;
     169             : 
     170             :             // non-pointer calculation in lhs and pointer in rhs => no clarification is needed
     171          14 :             if (tok->astOperand1()->isBinaryOp() && Token::Match(tok->astOperand1(), "%or%|&|%|*|/") && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->pointer > 0)
     172           2 :                 continue;
     173             : 
     174             :             // bit operation in lhs and char literals in rhs => probably no mistake
     175          12 :             if (tok->astOperand1()->tokType() == Token::eBitOp && Token::Match(tok->astOperand2()->astOperand1(), "%char%") && Token::Match(tok->astOperand2()->astOperand2(), "%char%"))
     176           1 :                 continue;
     177             : 
     178             :             // 2nd operand in lhs has known integer value => probably no mistake
     179          11 :             if (tok->astOperand1()->isBinaryOp() && tok->astOperand1()->astOperand2()->hasKnownIntValue()) {
     180           3 :                 const Token *op = tok->astOperand1()->astOperand2();
     181           3 :                 if (op->isNumber())
     182           2 :                     continue;
     183           1 :                 if (op->valueType() && op->valueType()->isEnum())
     184           1 :                     continue;
     185             :             }
     186             : 
     187             :             // Is code clarified by parentheses already?
     188           8 :             const Token *tok2 = tok->astOperand1();
     189          25 :             for (; tok2; tok2 = tok2->next()) {
     190          25 :                 if (tok2->str() == "(")
     191           2 :                     tok2 = tok2->link();
     192          23 :                 else if (tok2->str() == ")")
     193           1 :                     break;
     194          22 :                 else if (tok2->str() == "?") {
     195           7 :                     clarifyCalculationError(tok, tok->astOperand1()->str());
     196           7 :                     break;
     197             :                 }
     198             :             }
     199             :         }
     200             :     }
     201             : }
     202             : 
     203          11 : void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op)
     204             : {
     205             :     // suspicious calculation
     206          22 :     const std::string calc("'a" + op + "b?c:d'");
     207             : 
     208             :     // recommended calculation #1
     209          22 :     const std::string s1("'(a" + op + "b)?c:d'");
     210             : 
     211             :     // recommended calculation #2
     212          11 :     const std::string s2("'a" + op + "(b?c:d)'");
     213             : 
     214          11 :     reportError(tok,
     215             :                 Severity::style,
     216             :                 "clarifyCalculation",
     217          22 :                 "Clarify calculation precedence for '" + op + "' and '?'.\n"
     218             :                 "Suspicious calculation. Please use parentheses to clarify the code. "
     219          22 :                 "The code '" + calc + "' should be written as either '" + s1 + "' or '" + s2 + "'.", CWE783, Certainty::normal);
     220          11 : }
     221             : 
     222             : //---------------------------------------------------------------------------
     223             : // Clarify (meaningless) statements like *foo++; with parentheses.
     224             : //---------------------------------------------------------------------------
     225        3807 : void CheckOther::clarifyStatement()
     226             : {
     227        3807 :     if (!mSettings->severity.isEnabled(Severity::warning))
     228        2322 :         return;
     229             : 
     230        1485 :     logChecker("CheckOther::clarifyStatement"); // warning
     231             : 
     232        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     233        8648 :     for (const Scope * scope : symbolDatabase->functionScopes) {
     234      241689 :         for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
     235      234526 :             if (tok->astOperand1() && Token::Match(tok, "* %name%")) {
     236         297 :                 const Token *tok2 = tok->previous();
     237             : 
     238         306 :                 while (tok2 && tok2->str() == "*")
     239           9 :                     tok2 = tok2->previous();
     240             : 
     241         297 :                 if (tok2 && !tok2->astParent() && Token::Match(tok2, "[{};]")) {
     242          59 :                     tok2 = tok->astOperand1();
     243          59 :                     if (Token::Match(tok2, "++|-- [;,]"))
     244           7 :                         clarifyStatementError(tok2);
     245             :                 }
     246             :             }
     247             :         }
     248             :     }
     249             : }
     250             : 
     251          11 : void CheckOther::clarifyStatementError(const Token *tok)
     252             : {
     253          11 :     reportError(tok, Severity::warning, "clarifyStatement", "In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'?\n"
     254             :                 "A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. "
     255          22 :                 "Thus, the dereference is meaningless. Did you intend to write '(*A)++;'?", CWE783, Certainty::normal);
     256          11 : }
     257             : 
     258             : //---------------------------------------------------------------------------
     259             : // Check for suspicious occurrences of 'if(); {}'.
     260             : //---------------------------------------------------------------------------
     261        3807 : void CheckOther::checkSuspiciousSemicolon()
     262             : {
     263        3807 :     if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
     264        2420 :         return;
     265             : 
     266        1387 :     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
     267             : 
     268        1387 :     logChecker("CheckOther::checkSuspiciousSemicolon"); // warning,inconclusive
     269             : 
     270             :     // Look for "if(); {}", "for(); {}" or "while(); {}"
     271       11637 :     for (const Scope &scope : symbolDatabase->scopeList) {
     272       10250 :         if (scope.type == Scope::eIf || scope.type == Scope::eElse || scope.type == Scope::eWhile || scope.type == Scope::eFor) {
     273             :             // Ensure the semicolon is at the same line number as the if/for/while statement
     274             :             // and the {..} block follows it without an extra empty line.
     275        1170 :             if (Token::simpleMatch(scope.bodyStart, "{ ; } {") &&
     276          11 :                 scope.bodyStart->previous()->linenr() == scope.bodyStart->tokAt(2)->linenr() &&
     277        1175 :                 scope.bodyStart->linenr()+1 >= scope.bodyStart->tokAt(3)->linenr() &&
     278           4 :                 !scope.bodyStart->tokAt(3)->isExpandedMacro()) {
     279           3 :                 suspiciousSemicolonError(scope.classDef);
     280             :             }
     281             :         }
     282             :     }
     283             : }
     284             : 
     285           7 : void CheckOther::suspiciousSemicolonError(const Token* tok)
     286             : {
     287           7 :     reportError(tok, Severity::warning, "suspiciousSemicolon",
     288          14 :                 "Suspicious use of ; at the end of '" + (tok ? tok->str() : std::string()) + "' statement.", CWE398, Certainty::normal);
     289           7 : }
     290             : 
     291             : 
     292             : //---------------------------------------------------------------------------
     293             : // For C++ code, warn if C-style casts are used on pointer types
     294             : //---------------------------------------------------------------------------
     295        3830 : void CheckOther::warningOldStylePointerCast()
     296             : {
     297             :     // Only valid on C++ code
     298        3830 :     if (!mTokenizer->isCPP())
     299         105 :         return;
     300             : 
     301        3725 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("cstyleCast"))
     302        2320 :         return;
     303             : 
     304        1405 :     logChecker("CheckOther::warningOldStylePointerCast"); // style,c++
     305             : 
     306        1405 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     307        5961 :     for (const Scope * scope : symbolDatabase->functionScopes) {
     308             :         const Token* tok;
     309        4556 :         if (scope->function && scope->function->isConstructor())
     310          56 :             tok = scope->classDef;
     311             :         else
     312        4500 :             tok = scope->bodyStart;
     313      138271 :         for (; tok && tok != scope->bodyEnd; tok = tok->next()) {
     314             :             // Old style pointer casting..
     315      133715 :             if (tok->str() != "(")
     316      119704 :                 continue;
     317       14011 :             const Token* castTok = tok->next();
     318       19399 :             while (Token::Match(castTok, "const|volatile|class|struct|union|%type%|::")) {
     319        5388 :                 castTok = castTok->next();
     320        5388 :                 if (Token::simpleMatch(castTok, "<") && castTok->link())
     321          46 :                     castTok = castTok->link()->next();
     322             :             }
     323       14011 :             if (castTok == tok->next())
     324        9168 :                 continue;
     325        4843 :             bool isPtr = false, isRef = false;
     326        5012 :             while (Token::Match(castTok, "*|const|&")) {
     327         169 :                 if (castTok->str() == "*")
     328         117 :                     isPtr = true;
     329          52 :                 else if (castTok->str() == "&")
     330          48 :                     isRef = true;
     331         169 :                 castTok = castTok->next();
     332             :             }
     333        4843 :             if ((!isPtr && !isRef) || !Token::Match(castTok, ") (| %name%|%num%|%bool%|%char%|%str%|&"))
     334        4744 :                 continue;
     335             : 
     336          99 :             if (Token::Match(tok->previous(), "%type%"))
     337           1 :                 continue;
     338             : 
     339             :             // skip first "const" in "const Type* const"
     340         121 :             while (Token::Match(tok->next(), "const|volatile|class|struct|union"))
     341          23 :                 tok = tok->next();
     342          98 :             const Token* typeTok = tok->next();
     343             :             // skip second "const" in "const Type* const"
     344          98 :             if (tok->strAt(3) == "const")
     345           3 :                 tok = tok->next();
     346             : 
     347          98 :             const Token *p = tok->tokAt(4);
     348          98 :             if (p->hasKnownIntValue() && p->values().front().intvalue==0) // Casting nullpointers is safe
     349          19 :                 continue;
     350             : 
     351          79 :             if (typeTok->tokType() == Token::eType || typeTok->tokType() == Token::eName)
     352          79 :                 cstyleCastError(tok, isPtr);
     353             :         }
     354             :     }
     355             : }
     356             : 
     357          83 : void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
     358             : {
     359          83 :     const std::string type = isPtr ? "pointer" : "reference";
     360          83 :     reportError(tok, Severity::style, "cstyleCast",
     361         166 :                 "C-style " + type + " casting\n"
     362         166 :                 "C-style " + type + " casting detected. C++ offers four different kinds of casts as replacements: "
     363             :                 "static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to "
     364             :                 "any of those automatically, thus it is considered safer if the programmer explicitly states "
     365         166 :                 "which kind of cast is expected.", CWE398, Certainty::normal);
     366          83 : }
     367             : 
     368             : //---------------------------------------------------------------------------
     369             : // float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
     370             : //---------------------------------------------------------------------------
     371             : 
     372        3819 : void CheckOther::invalidPointerCast()
     373             : {
     374        3819 :     if (!mSettings->severity.isEnabled(Severity::portability))
     375        2323 :         return;
     376             : 
     377        1496 :     logChecker("CheckOther::invalidPointerCast"); // portability
     378             : 
     379        1496 :     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     380        1496 :     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
     381        8669 :     for (const Scope * scope : symbolDatabase->functionScopes) {
     382      234728 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
     383      227555 :             const Token* toTok = nullptr;
     384      227555 :             const Token* fromTok = nullptr;
     385             :             // Find cast
     386      227555 :             if (Token::Match(tok, "( const|volatile| const|volatile| %type% %type%| const| * )")) {
     387         187 :                 toTok = tok;
     388         187 :                 fromTok = tok->astOperand1();
     389      227368 :             } else if (Token::simpleMatch(tok, "reinterpret_cast <") && tok->linkAt(1)) {
     390           6 :                 toTok = tok->linkAt(1)->next();
     391           6 :                 fromTok = toTok->astOperand2();
     392             :             }
     393      227555 :             if (!fromTok)
     394      227362 :                 continue;
     395             : 
     396         193 :             const ValueType* fromType = fromTok->valueType();
     397         193 :             const ValueType* toType = toTok->valueType();
     398         193 :             if (!fromType || !toType || !fromType->pointer || !toType->pointer)
     399         107 :                 continue;
     400             : 
     401          86 :             if (fromType->type != toType->type && fromType->type >= ValueType::Type::BOOL && toType->type >= ValueType::Type::BOOL && (toType->type != ValueType::Type::CHAR || printInconclusive)) {
     402          15 :                 if (toType->isIntegral() && fromType->isIntegral())
     403           2 :                     continue;
     404             : 
     405          13 :                 invalidPointerCastError(tok, fromType->str(), toType->str(), toType->type == ValueType::Type::CHAR, toType->isIntegral());
     406             :             }
     407             :         }
     408             :     }
     409             : }
     410             : 
     411             : 
     412          17 : void CheckOther::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt)
     413             : {
     414          17 :     if (toIsInt) { // If we cast something to int*, this can be useful to play with its binary data representation
     415           3 :         reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + " to " + to + " is not portable due to different binary data representations on different platforms.", CWE704, inconclusive ? Certainty::inconclusive : Certainty::normal);
     416             :     } else
     417          14 :         reportError(tok, Severity::portability, "invalidPointerCast", "Casting between " + from + " and " + to + " which have an incompatible binary data representation.", CWE704, Certainty::normal);
     418          17 : }
     419             : 
     420             : 
     421             : //---------------------------------------------------------------------------
     422             : // Detect redundant assignments: x = 0; x = 4;
     423             : //---------------------------------------------------------------------------
     424             : 
     425        3804 : void CheckOther::checkRedundantAssignment()
     426             : {
     427        3804 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantAssignment"))
     428        2321 :         return;
     429             : 
     430        1486 :     logChecker("CheckOther::checkRedundantAssignment"); // style
     431             : 
     432        1486 :     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
     433        8649 :     for (const Scope *scope : symbolDatabase->functionScopes) {
     434        7163 :         if (!scope->bodyStart)
     435           0 :             continue;
     436      232843 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
     437      225706 :             if (Token::simpleMatch(tok, "] ("))
     438             :                 // todo: handle lambdas
     439          24 :                 break;
     440      225682 :             if (Token::simpleMatch(tok, "try {"))
     441             :                 // todo: check try blocks
     442           7 :                 tok = tok->linkAt(1);
     443      225682 :             if ((tok->isAssignmentOp() || tok->tokType() == Token::eIncDecOp) && tok->astOperand1()) {
     444        3398 :                 if (tok->astParent())
     445        3346 :                     continue;
     446             : 
     447             :                 // Do not warn about redundant initialization when rhs is trivial
     448             :                 // TODO : do not simplify the variable declarations
     449        3075 :                 bool isInitialization = false;
     450        3075 :                 if (Token::Match(tok->tokAt(-2), "; %var% =") && tok->tokAt(-2)->isSplittedVarDeclEq()) {
     451        1485 :                     isInitialization = true;
     452        1485 :                     bool trivial = true;
     453        1485 :                     visitAstNodes(tok->astOperand2(),
     454        1498 :                                   [&](const Token *rhs) {
     455        1498 :                         if (Token::simpleMatch(rhs, "{ 0 }"))
     456           8 :                             return ChildrenToVisit::none;
     457        1490 :                         if (Token::Match(rhs, "%str%|%num%|%name%") && !rhs->varId())
     458         559 :                             return ChildrenToVisit::none;
     459         931 :                         if (Token::Match(rhs, ":: %name%") && rhs->hasKnownIntValue())
     460           1 :                             return ChildrenToVisit::none;
     461         930 :                         if (rhs->isCast())
     462          70 :                             return ChildrenToVisit::op2;
     463         860 :                         trivial = false;
     464         860 :                         return ChildrenToVisit::done;
     465             :                     });
     466        1485 :                     if (trivial)
     467         625 :                         continue;
     468             :                 }
     469             : 
     470        2450 :                 const Token* rhs = tok->astOperand2();
     471             :                 // Do not warn about assignment with 0 / NULL
     472        2450 :                 if ((rhs && MathLib::isNullValue(rhs->str())) || isNullOperand(rhs))
     473          79 :                     continue;
     474             : 
     475        2371 :                 if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference())
     476             :                     // todo: check references
     477         102 :                     continue;
     478             : 
     479        2269 :                 if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isStatic())
     480             :                     // todo: check static variables
     481           8 :                     continue;
     482             : 
     483        2261 :                 bool inconclusive = false;
     484        2261 :                 if (tok->isCpp() && tok->astOperand1()->valueType()) {
     485             :                     // If there is a custom assignment operator => this is inconclusive
     486        1359 :                     if (tok->astOperand1()->valueType()->typeScope) {
     487          58 :                         const std::string op = "operator" + tok->str();
     488          58 :                         const std::list<Function>& fList = tok->astOperand1()->valueType()->typeScope->functionList;
     489          58 :                         inconclusive = std::any_of(fList.cbegin(), fList.cend(), [&](const Function& f) {
     490          35 :                             return f.name() == op;
     491             :                         });
     492             :                     }
     493             :                     // assigning a smart pointer has side effects
     494        1359 :                     if (tok->astOperand1()->valueType()->type == ValueType::SMART_POINTER)
     495           2 :                         break;
     496             :                 }
     497        2259 :                 if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive))
     498           0 :                     continue;
     499             : 
     500        2259 :                 FwdAnalysis fwdAnalysis(*mSettings);
     501        2259 :                 if (fwdAnalysis.hasOperand(tok->astOperand2(), tok->astOperand1()))
     502          77 :                     continue;
     503             : 
     504             :                 // Is there a redundant assignment?
     505             :                 const Token *start;
     506        2182 :                 if (tok->isAssignmentOp())
     507        2101 :                     start = tok->next();
     508             :                 else
     509          81 :                     start = tok->findExpressionStartEndTokens().second->next();
     510             : 
     511             :                 // Get next assignment..
     512        2182 :                 const Token *nextAssign = fwdAnalysis.reassign(tok->astOperand1(), start, scope->bodyEnd);
     513             : 
     514        2182 :                 if (!nextAssign)
     515        2132 :                     continue;
     516             : 
     517             :                 // there is redundant assignment. Is there a case between the assignments?
     518          50 :                 bool hasCase = false;
     519         716 :                 for (const Token *tok2 = tok; tok2 != nextAssign; tok2 = tok2->next()) {
     520         684 :                     if (tok2->str() == "break" || tok2->str() == "return")
     521           5 :                         break;
     522         679 :                     if (tok2->str() == "case") {
     523          13 :                         hasCase = true;
     524          13 :                         break;
     525             :                     }
     526             :                 }
     527             : 
     528             :                 // warn
     529          50 :                 if (hasCase)
     530          13 :                     redundantAssignmentInSwitchError(tok, nextAssign, tok->astOperand1()->expressionString());
     531          37 :                 else if (isInitialization)
     532           5 :                     redundantInitializationError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
     533             :                 else
     534          32 :                     redundantAssignmentError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
     535             :             }
     536             :         }
     537             :     }
     538             : }
     539             : 
     540           4 : void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var)
     541             : {
     542           4 :     const std::list<const Token *> callstack = { tok1, tok2 };
     543           4 :     reportError(callstack, Severity::performance, "redundantCopy",
     544           8 :                 "$symbol:" + var + "\n"
     545           8 :                 "Buffer '$symbol' is being written before its old content has been used.", CWE563, Certainty::normal);
     546           4 : }
     547             : 
     548          36 : void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
     549             : {
     550         216 :     const ErrorPath errorPath = { ErrorPathItem(tok1, var + " is assigned"), ErrorPathItem(tok2, var + " is overwritten") };
     551          36 :     if (inconclusive)
     552           1 :         reportError(errorPath, Severity::style, "redundantAssignment",
     553           2 :                     "$symbol:" + var + "\n"
     554             :                     "Variable '$symbol' is reassigned a value before the old one has been used if variable is no semaphore variable.\n"
     555           1 :                     "Variable '$symbol' is reassigned a value before the old one has been used. Make sure that this variable is not used like a semaphore in a threading environment before simplifying this code.", CWE563, Certainty::inconclusive);
     556             :     else
     557          35 :         reportError(errorPath, Severity::style, "redundantAssignment",
     558          70 :                     "$symbol:" + var + "\n"
     559          35 :                     "Variable '$symbol' is reassigned a value before the old one has been used.", CWE563, Certainty::normal);
     560          36 : }
     561             : 
     562           9 : void CheckOther::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
     563             : {
     564          45 :     const ErrorPath errorPath = { ErrorPathItem(tok1, var + " is initialized"), ErrorPathItem(tok2, var + " is overwritten") };
     565          18 :     reportError(errorPath, Severity::style, "redundantInitialization",
     566          18 :                 "$symbol:" + var + "\nRedundant initialization for '$symbol'. The initialized value is overwritten before it is read.",
     567             :                 CWE563,
     568             :                 inconclusive ? Certainty::inconclusive : Certainty::normal);
     569           9 : }
     570             : 
     571          17 : void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
     572             : {
     573          68 :     const ErrorPath errorPath = { ErrorPathItem(tok1, "$symbol is assigned"), ErrorPathItem(tok2, "$symbol is overwritten") };
     574          17 :     reportError(errorPath, Severity::style, "redundantAssignInSwitch",
     575          34 :                 "$symbol:" + var + "\n"
     576          17 :                 "Variable '$symbol' is reassigned a value before the old one has been used. 'break;' missing?", CWE563, Certainty::normal);
     577          17 : }
     578             : 
     579             : 
     580             : //---------------------------------------------------------------------------
     581             : //    switch (x)
     582             : //    {
     583             : //        case 2:
     584             : //            y = a;        // <- this assignment is redundant
     585             : //        case 3:
     586             : //            y = b;        // <- case 2 falls through and sets y twice
     587             : //    }
     588             : //---------------------------------------------------------------------------
     589        1359 : static inline bool isFunctionOrBreakPattern(const Token *tok)
     590             : {
     591        1359 :     return Token::Match(tok, "%name% (") || Token::Match(tok, "break|continue|return|exit|goto|throw");
     592             : }
     593             : 
     594        3807 : void CheckOther::redundantBitwiseOperationInSwitchError()
     595             : {
     596        3807 :     if (!mSettings->severity.isEnabled(Severity::warning))
     597        2322 :         return;
     598             : 
     599        1485 :     logChecker("CheckOther::redundantBitwiseOperationInSwitch"); // warning
     600             : 
     601        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     602             : 
     603             :     // Find the beginning of a switch. E.g.:
     604             :     //   switch (var) { ...
     605       12048 :     for (const Scope &switchScope : symbolDatabase->scopeList) {
     606       10563 :         if (switchScope.type != Scope::eSwitch || !switchScope.bodyStart)
     607       10486 :             continue;
     608             : 
     609             :         // Check the contents of the switch statement
     610         154 :         std::map<int, const Token*> varsWithBitsSet;
     611         154 :         std::map<int, std::string> bitOperations;
     612             : 
     613        1388 :         for (const Token *tok2 = switchScope.bodyStart->next(); tok2 != switchScope.bodyEnd; tok2 = tok2->next()) {
     614        1311 :             if (tok2->str() == "{") {
     615             :                 // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
     616             :                 //   case 3: b = 1;
     617             :                 //   case 4: if (a) { b = 2; }    // Doesn't make the b=1 redundant because it's conditional
     618          18 :                 if (Token::Match(tok2->previous(), ")|else {") && tok2->link()) {
     619          11 :                     const Token* endOfConditional = tok2->link();
     620          67 :                     for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) {
     621          56 :                         if (tok3->varId() != 0) {
     622           8 :                             varsWithBitsSet.erase(tok3->varId());
     623           8 :                             bitOperations.erase(tok3->varId());
     624          48 :                         } else if (isFunctionOrBreakPattern(tok3)) {
     625           7 :                             varsWithBitsSet.clear();
     626           7 :                             bitOperations.clear();
     627             :                         }
     628             :                     }
     629          11 :                     tok2 = endOfConditional;
     630             :                 }
     631             :             }
     632             : 
     633             :             // Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
     634             :             //    case 3: b = 1;    // <== redundant
     635             :             //    case 4: b = 2;
     636             : 
     637        1311 :             if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;")) {
     638          50 :                 varsWithBitsSet.erase(tok2->varId());
     639          50 :                 bitOperations.erase(tok2->varId());
     640             :             }
     641             : 
     642             :             // Bitwise operation. Report an error if it's performed twice before a break. E.g.:
     643             :             //    case 3: b |= 1;    // <== redundant
     644             :             //    case 4: b |= 1;
     645        1282 :             else if (Token::Match(tok2->previous(), ";|{|}|: %var% %assign% %num% ;") &&
     646        1287 :                      (tok2->strAt(1) == "|=" || tok2->strAt(1) == "&=") &&
     647          19 :                      Token::Match(tok2->next()->astOperand2(), "%num%")) {
     648          38 :                 const std::string bitOp = tok2->strAt(1)[0] + tok2->strAt(2);
     649          19 :                 const std::map<int, const Token*>::const_iterator i2 = varsWithBitsSet.find(tok2->varId());
     650             : 
     651             :                 // This variable has not had a bit operation performed on it yet, so just make a note of it
     652          19 :                 if (i2 == varsWithBitsSet.end()) {
     653          13 :                     varsWithBitsSet[tok2->varId()] = tok2;
     654          13 :                     bitOperations[tok2->varId()] = bitOp;
     655             :                 }
     656             : 
     657             :                 // The same bit operation has been performed on the same variable twice, so report an error
     658           6 :                 else if (bitOperations[tok2->varId()] == bitOp)
     659           3 :                     redundantBitwiseOperationInSwitchError(i2->second, i2->second->str());
     660             : 
     661             :                 // A different bit operation was performed on the variable, so clear it
     662             :                 else {
     663           3 :                     varsWithBitsSet.erase(tok2->varId());
     664           3 :                     bitOperations.erase(tok2->varId());
     665             :                 }
     666             :             }
     667             : 
     668             :             // Bitwise operation. Report an error if it's performed twice before a break. E.g.:
     669             :             //    case 3: b = b | 1;    // <== redundant
     670             :             //    case 4: b = b | 1;
     671        1244 :             else if (Token::Match(tok2->previous(), ";|{|}|: %var% = %name% %or%|& %num% ;") &&
     672           2 :                      tok2->varId() == tok2->tokAt(2)->varId()) {
     673           4 :                 const std::string bitOp = tok2->strAt(3) + tok2->strAt(4);
     674           2 :                 const std::map<int, const Token*>::const_iterator i2 = varsWithBitsSet.find(tok2->varId());
     675             : 
     676             :                 // This variable has not had a bit operation performed on it yet, so just make a note of it
     677           2 :                 if (i2 == varsWithBitsSet.end()) {
     678           1 :                     varsWithBitsSet[tok2->varId()] = tok2;
     679           1 :                     bitOperations[tok2->varId()] = bitOp;
     680             :                 }
     681             : 
     682             :                 // The same bit operation has been performed on the same variable twice, so report an error
     683           1 :                 else if (bitOperations[tok2->varId()] == bitOp)
     684           1 :                     redundantBitwiseOperationInSwitchError(i2->second, i2->second->str());
     685             : 
     686             :                 // A different bit operation was performed on the variable, so clear it
     687             :                 else {
     688           0 :                     varsWithBitsSet.erase(tok2->varId());
     689           0 :                     bitOperations.erase(tok2->varId());
     690             :                 }
     691             :             }
     692             : 
     693             :             // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
     694             :             //    case 3: b = 1;
     695             :             //    case 4: b++;
     696        1240 :             else if (tok2->varId() != 0 && tok2->strAt(1) != "|" && tok2->strAt(1) != "&") {
     697          55 :                 varsWithBitsSet.erase(tok2->varId());
     698          55 :                 bitOperations.erase(tok2->varId());
     699             :             }
     700             : 
     701             :             // Reset our record of assignments if there is a break or function call. E.g.:
     702             :             //    case 3: b = 1; break;
     703        1311 :             if (isFunctionOrBreakPattern(tok2)) {
     704          84 :                 varsWithBitsSet.clear();
     705          84 :                 bitOperations.clear();
     706             :             }
     707             :         }
     708             :     }
     709             : }
     710             : 
     711           8 : void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname)
     712             : {
     713           8 :     reportError(tok, Severity::style,
     714             :                 "redundantBitwiseOperationInSwitch",
     715          16 :                 "$symbol:" + varname + "\n"
     716          16 :                 "Redundant bitwise operation on '$symbol' in 'switch' statement. 'break;' missing?");
     717           8 : }
     718             : 
     719             : 
     720             : //---------------------------------------------------------------------------
     721             : // Check for statements like case A||B: in switch()
     722             : //---------------------------------------------------------------------------
     723        3807 : void CheckOther::checkSuspiciousCaseInSwitch()
     724             : {
     725        3807 :     if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
     726        2420 :         return;
     727             : 
     728        1387 :     logChecker("CheckOther::checkSuspiciousCaseInSwitch"); // warning,inconclusive
     729             : 
     730        1387 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     731             : 
     732       11637 :     for (const Scope & scope : symbolDatabase->scopeList) {
     733       10250 :         if (scope.type != Scope::eSwitch)
     734       10180 :             continue;
     735             : 
     736        1299 :         for (const Token* tok = scope.bodyStart->next(); tok != scope.bodyEnd; tok = tok->next()) {
     737        1229 :             if (tok->str() == "case") {
     738         123 :                 const Token* finding = nullptr;
     739         257 :                 for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
     740         257 :                     if (tok2->str() == ":")
     741         123 :                         break;
     742         134 :                     if (Token::Match(tok2, "[;}{]"))
     743           0 :                         break;
     744             : 
     745         134 :                     if (tok2->str() == "?")
     746           0 :                         finding = nullptr;
     747         134 :                     else if (Token::Match(tok2, "&&|%oror%"))
     748           3 :                         finding = tok2;
     749             :                 }
     750         123 :                 if (finding)
     751           3 :                     suspiciousCaseInSwitchError(finding, finding->str());
     752             :             }
     753             :         }
     754             :     }
     755             : }
     756             : 
     757           7 : void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
     758             : {
     759           7 :     reportError(tok, Severity::warning, "suspiciousCase",
     760          14 :                 "Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n"
     761          14 :                 "Using an operator like '" + operatorString + "' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead?", CWE398, Certainty::inconclusive);
     762           7 : }
     763             : 
     764             : //---------------------------------------------------------------------------
     765             : //    Find consecutive return, break, continue, goto or throw statements. e.g.:
     766             : //        break; break;
     767             : //    Detect dead code, that follows such a statement. e.g.:
     768             : //        return(0); foo();
     769             : //---------------------------------------------------------------------------
     770        3807 : void CheckOther::checkUnreachableCode()
     771             : {
     772             :     // misra-c-2012-2.1
     773             :     // misra-c-2023-2.1
     774             :     // misra-cpp-2008-0-1-1
     775             :     // autosar
     776        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unreachableCode"))
     777        2320 :         return;
     778             : 
     779        1486 :     logChecker("CheckOther::checkUnreachableCode"); // style
     780             : 
     781        1486 :     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     782        1486 :     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
     783        8649 :     for (const Scope * scope : symbolDatabase->functionScopes) {
     784      139667 :         for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
     785      132506 :             const Token* secondBreak = nullptr;
     786      132506 :             const Token* labelName = nullptr;
     787      132506 :             if (tok->link() && Token::Match(tok, "(|[|<"))
     788       25706 :                 tok = tok->link();
     789      106800 :             else if (Token::Match(tok, "break|continue ;"))
     790          58 :                 secondBreak = tok->tokAt(2);
     791      106742 :             else if (Token::Match(tok, "[;{}:] return|throw") && tok->next()->isKeyword()) {
     792        1283 :                 if (Token::simpleMatch(tok->astParent(), "?"))
     793           1 :                     continue;
     794        1282 :                 tok = tok->next(); // tok should point to return or throw
     795        4215 :                 for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
     796        4213 :                     if (tok2->str() == "(" || tok2->str() == "{")
     797         695 :                         tok2 = tok2->link();
     798        4213 :                     if (tok2->str() == ";") {
     799        1280 :                         secondBreak = tok2->next();
     800        1280 :                         break;
     801             :                     }
     802             :                 }
     803      105459 :             } else if (Token::Match(tok, "goto %any% ;")) {
     804           7 :                 secondBreak = tok->tokAt(3);
     805           7 :                 labelName = tok->next();
     806      105452 :             } else if (Token::Match(tok, "%name% (") && mSettings->library.isnoreturn(tok) && !Token::Match(tok->next()->astParent(), "?|:")) {
     807          49 :                 if ((!tok->function() || (tok->function()->token != tok && tok->function()->tokenDef != tok)) && tok->linkAt(1)->strAt(1) != "{")
     808          49 :                     secondBreak = tok->linkAt(1)->tokAt(2);
     809          49 :                 if (Token::simpleMatch(secondBreak, "return")) {
     810             :                     // clarification for tools that function returns
     811           1 :                     continue;
     812             :                 }
     813             :             }
     814             : 
     815             :             // Statements follow directly, no line between them. (#3383)
     816             :             // TODO: Try to find a better way to avoid false positives due to preprocessor configurations.
     817      132504 :             const bool inconclusive = secondBreak && (secondBreak->linenr() - 1 > secondBreak->previous()->linenr());
     818             : 
     819      132504 :             if (secondBreak && (printInconclusive || !inconclusive)) {
     820        1392 :                 if (Token::Match(secondBreak, "continue|goto|throw|return") && secondBreak->isKeyword()) {
     821           9 :                     duplicateBreakError(secondBreak, inconclusive);
     822           9 :                     tok = Token::findmatch(secondBreak, "[}:]");
     823        1383 :                 } else if (secondBreak->str() == "break") { // break inside switch as second break statement should not issue a warning
     824           4 :                     if (tok->str() == "break") // If the previous was a break, too: Issue warning
     825           2 :                         duplicateBreakError(secondBreak, inconclusive);
     826             :                     else {
     827           2 :                         if (tok->scope()->type != Scope::eSwitch) // Check, if the enclosing scope is a switch
     828           2 :                             duplicateBreakError(secondBreak, inconclusive);
     829             :                     }
     830           4 :                     tok = Token::findmatch(secondBreak, "[}:]");
     831        1379 :                 } else if (!Token::Match(secondBreak, "return|}|case|default") && secondBreak->strAt(1) != ":") { // TODO: No bailout for unconditional scopes
     832             :                     // If the goto label is followed by a loop construct in which the label is defined it's quite likely
     833             :                     // that the goto jump was intended to skip some code on the first loop iteration.
     834          18 :                     bool labelInFollowingLoop = false;
     835          18 :                     if (labelName && Token::Match(secondBreak, "while|do|for")) {
     836           3 :                         const Token *scope2 = Token::findsimplematch(secondBreak, "{");
     837           3 :                         if (scope2) {
     838          15 :                             for (const Token *tokIter = scope2; tokIter != scope2->link() && tokIter; tokIter = tokIter->next()) {
     839          15 :                                 if (Token::Match(tokIter, "[;{}] %any% :") && labelName->str() == tokIter->strAt(1)) {
     840           3 :                                     labelInFollowingLoop = true;
     841           3 :                                     break;
     842             :                                 }
     843             :                             }
     844             :                         }
     845             :                     }
     846             : 
     847             :                     // hide FP for statements that just hide compiler warnings about unused function arguments
     848          18 :                     bool silencedCompilerWarningOnly = false;
     849          18 :                     const Token *silencedWarning = secondBreak;
     850             :                     for (;;) {
     851          23 :                         if (Token::Match(silencedWarning, "( void ) %name% ;")) {
     852           5 :                             silencedWarning = silencedWarning->tokAt(5);
     853           5 :                             continue;
     854             :                         }
     855          18 :                         if (silencedWarning && silencedWarning == scope->bodyEnd)
     856           2 :                             silencedCompilerWarningOnly = true;
     857          18 :                         break;
     858             :                     }
     859          18 :                     if (silencedWarning)
     860          18 :                         secondBreak = silencedWarning;
     861             : 
     862          18 :                     if (!labelInFollowingLoop && !silencedCompilerWarningOnly)
     863          13 :                         unreachableCodeError(secondBreak, tok, inconclusive);
     864          18 :                     tok = Token::findmatch(secondBreak, "[}:]");
     865        1361 :                 } else if (secondBreak->scope() && secondBreak->scope()->isLoopScope() && secondBreak->str() == "}" && tok->str() == "continue") {
     866           2 :                     redundantContinueError(tok);
     867           2 :                     tok = secondBreak;
     868             :                 } else
     869        1359 :                     tok = secondBreak;
     870             : 
     871        1392 :                 if (!tok)
     872           2 :                     break;
     873        1390 :                 tok = tok->previous(); // Will be advanced again by for loop
     874             :             }
     875             :         }
     876             :     }
     877             : }
     878             : 
     879          17 : void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
     880             : {
     881          34 :     reportError(tok, Severity::style, "duplicateBreak",
     882             :                 "Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
     883             :                 "Consecutive return, break, continue, goto or throw statements are unnecessary. "
     884          34 :                 "The second statement can never be executed, and so should be removed.", CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
     885          17 : }
     886             : 
     887          17 : void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive)
     888             : {
     889          34 :     std::string msg = "Statements following ";
     890          17 :     if (noreturn && (noreturn->function() || mSettings->library.isnoreturn(noreturn)))
     891           7 :         msg += "noreturn function '" + noreturn->str() + "()'";
     892          10 :     else if (noreturn && noreturn->isKeyword())
     893           6 :         msg += "'" + noreturn->str() + "'";
     894             :     else
     895           4 :         msg += "return, break, continue, goto or throw";
     896          17 :     msg += " will never be executed.";
     897          34 :     reportError(tok, Severity::style, "unreachableCode",
     898          34 :                 msg, CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
     899          17 : }
     900             : 
     901           2 : void CheckOther::redundantContinueError(const Token *tok)
     902             : {
     903           2 :     reportError(tok, Severity::style, "redundantContinue",
     904           4 :                 "'continue' is redundant since it is the last statement in a loop.", CWE561, Certainty::normal);
     905           2 : }
     906             : 
     907        1742 : static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings& settings) {
     908        1742 :     if (!tok)
     909           1 :         return false;
     910        1741 :     if (tok->isNumber() || tok->tokType() == Token::eString || tok->tokType() == Token::eChar || tok->isBoolean())
     911         535 :         return true;
     912        1206 :     bool needsCheck = tok->varId() > 0;
     913        1206 :     if (!needsCheck) {
     914        1132 :         if (tok->isArithmeticalOp())
     915         105 :             return isSimpleExpr(tok->astOperand1(), var, settings) && (!tok->astOperand2() || isSimpleExpr(tok->astOperand2(), var, settings));
     916        1027 :         const Token* ftok = tok->previous();
     917        2393 :         if (Token::Match(ftok, "%name% (") &&
     918        1366 :             ((ftok->function() && ftok->function()->isConst()) || settings.library.isFunctionConst(ftok->str(), /*pure*/ true)))
     919         181 :             needsCheck = true;
     920         846 :         else if (tok->str() == "[") {
     921           5 :             needsCheck = tok->astOperand1() && tok->astOperand1()->varId() > 0;
     922           5 :             tok = tok->astOperand1();
     923             :         }
     924         841 :         else if (isLeafDot(tok->astOperand2())) {
     925          19 :             needsCheck = tok->astOperand2()->varId() > 0;
     926          19 :             tok = tok->astOperand2();
     927             :         }
     928             :     }
     929        1101 :     return (needsCheck && !findExpressionChanged(tok, tok->astParent(), var->scope()->bodyEnd, settings));
     930             : }
     931             : 
     932             : //---------------------------------------------------------------------------
     933             : // Check scope of variables..
     934             : //---------------------------------------------------------------------------
     935        3807 : void CheckOther::checkVariableScope()
     936             : {
     937        3807 :     if (mSettings->clang)
     938           0 :         return;
     939             : 
     940        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("variableScope"))
     941        2321 :         return;
     942             : 
     943        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     944             : 
     945             :     // In C it is common practice to declare local variables at the
     946             :     // start of functions.
     947        1486 :     if (mSettings->daca && mTokenizer->isC())
     948           0 :         return;
     949             : 
     950        1486 :     logChecker("CheckOther::checkVariableScope"); // style,notclang
     951             : 
     952       22896 :     for (const Variable* var : symbolDatabase->variableList()) {
     953       21410 :         if (!var || !var->isLocal() || var->isConst())
     954       11997 :             continue;
     955             : 
     956       12415 :         if (var->nameToken()->isExpandedMacro())
     957           2 :             continue;
     958             : 
     959       12413 :         const bool isPtrOrRef = var->isPointer() || var->isReference();
     960       12413 :         const bool isSimpleType = var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType() || (var->typeStartToken()->isC() && var->type() && var->type()->isStructType());
     961       12413 :         if (!isPtrOrRef && !isSimpleType && !astIsContainer(var->nameToken()))
     962        1965 :             continue;
     963             : 
     964       10448 :         if (mTokenizer->hasIfdef(var->nameToken(), var->scope()->bodyEnd))
     965          73 :             continue;
     966             : 
     967             :         // reference of range for loop variable..
     968       10375 :         if (Token::Match(var->nameToken()->previous(), "& %var% = %var% .")) {
     969           2 :             const Token *otherVarToken = var->nameToken()->tokAt(2);
     970           2 :             const Variable *otherVar = otherVarToken->variable();
     971           3 :             if (otherVar && Token::Match(otherVar->nameToken(), "%var% :") &&
     972           5 :                 otherVar->nameToken()->next()->astParent() &&
     973           1 :                 Token::simpleMatch(otherVar->nameToken()->next()->astParent()->previous(), "for ("))
     974           1 :                 continue;
     975             :         }
     976             : 
     977       10374 :         bool forHead = false; // Don't check variables declared in header of a for loop
     978       22737 :         for (const Token* tok = var->typeStartToken(); tok; tok = tok->previous()) {
     979       22737 :             if (tok->str() == "(") {
     980          87 :                 forHead = true;
     981          87 :                 break;
     982             :             }
     983       22650 :             if (Token::Match(tok, "[;{}]"))
     984       10287 :                 break;
     985             :         }
     986       10374 :         if (forHead)
     987          87 :             continue;
     988             : 
     989       10287 :         const Token* tok = var->nameToken()->next();
     990       10287 :         bool isConstructor = false;
     991       10287 :         if (Token::Match(tok, "; %varid% =", var->declarationId())) { // bailout for assignment
     992        1491 :             tok = tok->tokAt(2)->astOperand2();
     993        1491 :             if (!isSimpleExpr(tok, var, *mSettings))
     994         852 :                 continue;
     995             :         }
     996        8796 :         else if (Token::Match(tok, "{|(")) { // bailout for constructor
     997          63 :             isConstructor = true;
     998          63 :             const Token* argTok = tok->astOperand2();
     999          63 :             bool bail = false;
    1000         138 :             while (argTok) {
    1001          83 :                 if (Token::simpleMatch(argTok, ",")) {
    1002          27 :                     if (!isSimpleExpr(argTok->astOperand2(), var, *mSettings)) {
    1003           5 :                         bail = true;
    1004           5 :                         break;
    1005             :                     }
    1006          56 :                 } else if (argTok->str() != "." && !isSimpleExpr(argTok, var, *mSettings)) {
    1007           3 :                     bail = true;
    1008           3 :                     break;
    1009             :                 }
    1010          75 :                 argTok = argTok->astOperand1();
    1011             :             }
    1012          63 :             if (bail)
    1013           8 :                 continue;
    1014             :         }
    1015             :         // bailout if initialized with function call that has possible side effects
    1016        9427 :         if (!isConstructor && Token::Match(tok, "[(=]") && Token::simpleMatch(tok->astOperand2(), "("))
    1017          14 :             continue;
    1018        9413 :         bool reduce = true;
    1019        9413 :         bool used = false; // Don't warn about unused variables
    1020      176893 :         for (; tok && tok != var->scope()->bodyEnd; tok = tok->next()) {
    1021      176739 :             if (tok->str() == "{" && tok->scope() != tok->previous()->scope() && !tok->isExpandedMacro() && !isWithinScope(tok, var, Scope::ScopeType::eLambda)) {
    1022         260 :                 if (used) {
    1023          14 :                     bool used2 = false;
    1024          14 :                     if (!checkInnerScope(tok, var, used2) || used2) {
    1025           9 :                         reduce = false;
    1026           9 :                         break;
    1027             :                     }
    1028         246 :                 } else if (!checkInnerScope(tok, var, used)) {
    1029          91 :                     reduce = false;
    1030          91 :                     break;
    1031             :                 }
    1032             : 
    1033         160 :                 tok = tok->link();
    1034             : 
    1035             :                 // parse else if blocks..
    1036      176479 :             } else if (Token::simpleMatch(tok, "else { if (") && Token::simpleMatch(tok->linkAt(3), ") {")) {
    1037           6 :                 tok = tok->next();
    1038      176473 :             } else if (tok->varId() == var->declarationId() || tok->str() == "goto") {
    1039        9159 :                 reduce = false;
    1040        9159 :                 break;
    1041             :             }
    1042             :         }
    1043             : 
    1044        9413 :         if (reduce && used)
    1045          36 :             variableScopeError(var->nameToken(), var->name());
    1046             :     }
    1047             : }
    1048             : 
    1049         276 : bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used) const
    1050             : {
    1051         276 :     const Scope* scope = tok->next()->scope();
    1052         276 :     bool loopVariable = scope->isLoopScope();
    1053         276 :     bool noContinue = true;
    1054         276 :     const Token* forHeadEnd = nullptr;
    1055         276 :     const Token* end = tok->link();
    1056         276 :     if (scope->type == Scope::eUnconditional && (tok->strAt(-1) == ")" || tok->previous()->isName())) // Might be an unknown macro like BOOST_FOREACH
    1057           4 :         loopVariable = true;
    1058             : 
    1059         276 :     if (scope->type == Scope::eDo) {
    1060          16 :         end = end->linkAt(2);
    1061         260 :     } else if (loopVariable && tok->strAt(-1) == ")") {
    1062          23 :         tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
    1063         237 :     } else if (scope->type == Scope::eSwitch) {
    1064          75 :         for (const Scope* innerScope : scope->nestedList) {
    1065          16 :             if (used) {
    1066           1 :                 bool used2 = false;
    1067           1 :                 if (!checkInnerScope(innerScope->bodyStart, var, used2) || used2) {
    1068           1 :                     return false;
    1069             :                 }
    1070          15 :             } else if (!checkInnerScope(innerScope->bodyStart, var, used)) {
    1071           0 :                 return false;
    1072             :             }
    1073             :         }
    1074             :     }
    1075             : 
    1076         275 :     bool bFirstAssignment=false;
    1077        2617 :     for (; tok && tok != end; tok = tok->next()) {
    1078        2432 :         if (tok->str() == "goto")
    1079           0 :             return false;
    1080        2432 :         if (tok->str() == "continue")
    1081           1 :             noContinue = false;
    1082             : 
    1083        2432 :         if (Token::simpleMatch(tok, "for ("))
    1084           4 :             forHeadEnd = tok->linkAt(1);
    1085        2432 :         if (tok == forHeadEnd)
    1086           4 :             forHeadEnd = nullptr;
    1087             : 
    1088        2432 :         if (loopVariable && noContinue && tok->scope() == scope && !forHeadEnd && scope->type != Scope::eSwitch && Token::Match(tok, "%varid% =", var->declarationId())) { // Assigned in outer scope.
    1089          17 :             loopVariable = false;
    1090          17 :             std::pair<const Token*, const Token*> range = tok->next()->findExpressionStartEndTokens();
    1091          17 :             if (range.first)
    1092          17 :                 range.first = range.first->next();
    1093          17 :             const Token* exprTok = findExpression(var->nameToken()->exprId(), range.first, range.second, [&](const Token* tok2) {
    1094           1 :                 return tok2->varId() == var->declarationId();
    1095          34 :             });
    1096          17 :             if (exprTok) {
    1097           1 :                 tok = exprTok;
    1098           1 :                 loopVariable = true;
    1099             :             }
    1100             :         }
    1101             : 
    1102        2432 :         if (loopVariable && Token::Match(tok, "%varid% !!=", var->declarationId())) // Variable used in loop
    1103          23 :             return false;
    1104             : 
    1105        2409 :         if (Token::Match(tok, "& %varid%", var->declarationId())) // Taking address of variable
    1106           2 :             return false;
    1107             : 
    1108        2407 :         if (Token::Match(tok, "%varid% =", var->declarationId())) {
    1109          83 :             if (!bFirstAssignment && var->isInit() && Token::findmatch(tok->tokAt(2), "%varid%", Token::findsimplematch(tok->tokAt(3), ";"), var->declarationId()))
    1110           2 :                 return false;
    1111          81 :             bFirstAssignment = true;
    1112             :         }
    1113             : 
    1114        2405 :         if (!bFirstAssignment && Token::Match(tok, "* %varid%", var->declarationId())) // dereferencing means access to previous content
    1115           1 :             return false;
    1116             : 
    1117        2404 :         if (Token::Match(tok, "= %varid%", var->declarationId()) && (var->isArray() || var->isPointer() || (var->valueType() && var->valueType()->container))) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
    1118           3 :             return false;
    1119             : 
    1120        2401 :         if (tok->varId() == var->declarationId()) {
    1121         199 :             used = true;
    1122         199 :             if (scope == tok->scope()) {
    1123         168 :                 if (scope->type == Scope::eSwitch)
    1124          56 :                     return false; // Used in outer switch scope - unsafe or impossible to reduce scope
    1125             : 
    1126         112 :                 if (scope->bodyStart && scope->bodyStart->isSimplifiedScope())
    1127           1 :                     return false; // simplified if/for/switch init statement
    1128             :             }
    1129         142 :             if (var->isArrayOrPointer()) {
    1130          19 :                 int argn{};
    1131          19 :                 if (const Token* ftok = getTokenArgumentFunction(tok, argn)) { // var passed to function?
    1132           6 :                     if (ftok->next()->astParent()) { // return value used?
    1133           2 :                         if (ftok->function() && Function::returnsPointer(ftok->function()))
    1134           2 :                             return false;
    1135           1 :                         const std::string ret = mSettings->library.returnValueType(ftok); // assume that var is returned
    1136           1 :                         if (!ret.empty() && ret.back() == '*')
    1137           1 :                             return false;
    1138             :                     }
    1139             :                 }
    1140             :             }
    1141             :         }
    1142             :     }
    1143             : 
    1144         185 :     return true;
    1145             : }
    1146             : 
    1147          40 : void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
    1148             : {
    1149          40 :     reportError(tok,
    1150             :                 Severity::style,
    1151             :                 "variableScope",
    1152          80 :                 "$symbol:" + varname + "\n"
    1153             :                 "The scope of the variable '$symbol' can be reduced.\n"
    1154             :                 "The scope of the variable '$symbol' can be reduced. Warning: Be careful "
    1155             :                 "when fixing this message, especially when there are inner loops. Here is an "
    1156             :                 "example where cppcheck will write that the scope for 'i' can be reduced:\n"
    1157             :                 "void f(int x)\n"
    1158             :                 "{\n"
    1159             :                 "    int i = 0;\n"
    1160             :                 "    if (x) {\n"
    1161             :                 "        // it's safe to move 'int i = 0;' here\n"
    1162             :                 "        for (int n = 0; n < 10; ++n) {\n"
    1163             :                 "            // it is possible but not safe to move 'int i = 0;' here\n"
    1164             :                 "            do_something(&i);\n"
    1165             :                 "        }\n"
    1166             :                 "    }\n"
    1167             :                 "}\n"
    1168          80 :                 "When you see this message it is always safe to reduce the variable scope 1 level.", CWE398, Certainty::normal);
    1169          40 : }
    1170             : 
    1171             : //---------------------------------------------------------------------------
    1172             : // Comma in return statement: return a+1, b++;. (experimental)
    1173             : //---------------------------------------------------------------------------
    1174        3807 : void CheckOther::checkCommaSeparatedReturn()
    1175             : {
    1176             :     // This is experimental for now. See #5076
    1177             :     if ((true) || !mSettings->severity.isEnabled(Severity::style)) // NOLINT(readability-simplify-boolean-expr)
    1178        3807 :         return;
    1179             : 
    1180             :     // logChecker
    1181             : 
    1182             :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    1183             :         if (tok->str() == "return") {
    1184             :             tok = tok->next();
    1185             :             while (tok && tok->str() != ";") {
    1186             :                 if (tok->link() && Token::Match(tok, "[([{<]"))
    1187             :                     tok = tok->link();
    1188             : 
    1189             :                 if (!tok->isExpandedMacro() && tok->str() == "," && tok->linenr() != tok->next()->linenr())
    1190             :                     commaSeparatedReturnError(tok);
    1191             : 
    1192             :                 tok = tok->next();
    1193             :             }
    1194             :             // bailout: missing semicolon (invalid code / bad tokenizer)
    1195             :             if (!tok)
    1196             :                 break;
    1197             :         }
    1198             :     }
    1199             : }
    1200             : 
    1201           4 : void CheckOther::commaSeparatedReturnError(const Token *tok)
    1202             : {
    1203           4 :     reportError(tok,
    1204             :                 Severity::style,
    1205             :                 "commaSeparatedReturn",
    1206             :                 "Comma is used in return statement. The comma can easily be misread as a ';'.\n"
    1207             :                 "Comma is used in return statement. When comma is used in a return statement it can "
    1208             :                 "easily be misread as a semicolon. For example in the code below the value "
    1209             :                 "of 'b' is returned if the condition is true, but it is easy to think that 'a+1' is "
    1210             :                 "returned:\n"
    1211             :                 "    if (x)\n"
    1212             :                 "        return a + 1,\n"
    1213             :                 "    b++;\n"
    1214             :                 "However it can be useful to use comma in macros. Cppcheck does not warn when such a "
    1215           8 :                 "macro is then used in a return statement, it is less likely such code is misunderstood.", CWE398, Certainty::normal);
    1216           4 : }
    1217             : 
    1218        3807 : void CheckOther::checkPassByReference()
    1219             : {
    1220        3807 :     if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC())
    1221        2426 :         return;
    1222             : 
    1223        1381 :     logChecker("CheckOther::checkPassByReference"); // performance,c++
    1224             : 
    1225        1381 :     const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
    1226             : 
    1227       14727 :     for (const Variable* var : symbolDatabase->variableList()) {
    1228       13346 :         if (!var || !var->isClass() || var->isPointer() || var->isArray() || var->isReference() || var->isEnumType())
    1229       10717 :             continue;
    1230             : 
    1231        2629 :         const bool isRangeBasedFor = astIsRangeBasedForDecl(var->nameToken());
    1232        2629 :         if (!var->isArgument() && !isRangeBasedFor)
    1233        2316 :             continue;
    1234             : 
    1235         313 :         if (!isRangeBasedFor && var->scope() && var->scope()->function->arg->link()->strAt(-1) == "...")
    1236           1 :             continue; // references could not be used as va_start parameters (#5824)
    1237             : 
    1238         312 :         const Token * const varDeclEndToken = var->declEndToken();
    1239         911 :         if ((varDeclEndToken && varDeclEndToken->isExternC()) ||
    1240         599 :             (var->scope() && var->scope()->function && var->scope()->function->tokenDef && var->scope()->function->tokenDef->isExternC()))
    1241           4 :             continue; // references cannot be used in functions in extern "C" blocks
    1242             : 
    1243         308 :         bool inconclusive = false;
    1244             : 
    1245         308 :         const bool isContainer = var->valueType() && var->valueType()->type == ValueType::Type::CONTAINER && var->valueType()->container && !var->valueType()->container->view;
    1246         308 :         if (!isContainer) {
    1247         209 :             if (var->type() && !var->type()->isEnumType()) { // Check if type is a struct or class.
    1248             :                 // Ensure that it is a large object.
    1249          56 :                 if (!var->type()->classScope)
    1250           1 :                     inconclusive = true;
    1251          55 :                 else if (!var->valueType() || ValueFlow::getSizeOf(*var->valueType(), *mSettings) <= 2 * mSettings->platform.sizeof_pointer)
    1252          28 :                     continue;
    1253             :             }
    1254             :             else
    1255         153 :                 continue;
    1256             :         }
    1257             : 
    1258         127 :         if (inconclusive && !mSettings->certainty.isEnabled(Certainty::inconclusive))
    1259           0 :             continue;
    1260             : 
    1261         127 :         const bool isConst = var->isConst();
    1262         127 :         if (isConst) {
    1263          14 :             passedByValueError(var, inconclusive, isRangeBasedFor);
    1264          14 :             continue;
    1265             :         }
    1266             : 
    1267             :         // Check if variable could be const
    1268         113 :         if (!isRangeBasedFor && (!var->scope() || var->scope()->function->isImplicitlyVirtual()))
    1269           9 :             continue;
    1270             : 
    1271         104 :         if (!isVariableChanged(var, *mSettings)) {
    1272          55 :             passedByValueError(var, inconclusive, isRangeBasedFor);
    1273             :         }
    1274             :     }
    1275             : }
    1276             : 
    1277          73 : void CheckOther::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor)
    1278             : {
    1279         146 :     std::string id = isRangeBasedFor ? "iterateByValue" : "passedByValue";
    1280         146 :     const std::string action = isRangeBasedFor ? "declared as": "passed by";
    1281         146 :     const std::string type = isRangeBasedFor ? "Range variable" : "Function parameter";
    1282         146 :     std::string msg = "$symbol:" + (var ? var->name() : "") + "\n" +
    1283         219 :                       type + " '$symbol' should be " + action + " const reference.";
    1284         146 :     ErrorPath errorPath;
    1285          73 :     if (var && var->scope() && var->scope()->function && var->scope()->function->functionPointerUsage) {
    1286           1 :         id += "Callback";
    1287           1 :         errorPath.emplace_front(var->scope()->function->functionPointerUsage, "Function pointer used here.");
    1288           1 :         msg += " However it seems that '" + var->scope()->function->name() + "' is a callback function.";
    1289             :     }
    1290          73 :     if (var)
    1291          69 :         errorPath.emplace_back(var->nameToken(), msg);
    1292          73 :     if (isRangeBasedFor)
    1293           1 :         msg += "\nVariable '$symbol' is used to iterate by value. It could be declared as a const reference which is usually faster and recommended in C++.";
    1294             :     else
    1295          72 :         msg += "\nParameter '$symbol' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.";
    1296          73 :     reportError(errorPath, Severity::performance, id.c_str(), msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
    1297          73 : }
    1298             : 
    1299           8 : static bool isVariableMutableInInitializer(const Token* start, const Token * end, nonneg int varid)
    1300             : {
    1301           8 :     if (!start)
    1302           0 :         return false;
    1303           8 :     if (!end)
    1304           0 :         return false;
    1305          35 :     for (const Token *tok = start; tok != end; tok = tok->next()) {
    1306          35 :         if (tok->varId() != varid)
    1307          27 :             continue;
    1308           8 :         if (tok->astParent()) {
    1309           8 :             const Token * memberTok = tok->astParent()->previous();
    1310           8 :             if (Token::Match(memberTok, "%var% (") && memberTok->variable()) {
    1311           5 :                 const Variable * memberVar = memberTok->variable();
    1312           5 :                 if (memberVar->isClass())
    1313             :                     //TODO: check if the called constructor could live with a const variable
    1314             :                     // pending that, assume the worst (that it can't)
    1315           4 :                     return true;
    1316           1 :                 if (!memberVar->isReference())
    1317           0 :                     continue;
    1318           1 :                 if (memberVar->isConst())
    1319           0 :                     continue;
    1320             :             }
    1321             :         }
    1322           4 :         return true;
    1323             :     }
    1324           0 :     return false;
    1325             : }
    1326             : 
    1327        3807 : void CheckOther::checkConstVariable()
    1328             : {
    1329        3807 :     if (!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC())
    1330        2425 :         return;
    1331             : 
    1332        1382 :     const SymbolDatabase *const symbolDatabase = mTokenizer->getSymbolDatabase();
    1333             : 
    1334       14731 :     for (const Variable *var : symbolDatabase->variableList()) {
    1335       13349 :         if (!var)
    1336        1495 :             continue;
    1337       11854 :         if (!var->isReference())
    1338       10573 :             continue;
    1339        1281 :         if (var->isRValueReference())
    1340           9 :             continue;
    1341        1272 :         if (var->isPointer())
    1342          14 :             continue;
    1343        1258 :         if (var->isConst())
    1344         758 :             continue;
    1345         500 :         const Scope* scope = var->scope();
    1346         500 :         if (!scope)
    1347          16 :             continue;
    1348         484 :         const Function* function = scope->function;
    1349         484 :         if (!function && !scope->isLocal())
    1350           2 :             continue;
    1351         482 :         if (function && var->isArgument()) {
    1352         424 :             if (function->isImplicitlyVirtual() || function->templateDef)
    1353           3 :                 continue;
    1354         421 :             if (function->isConstructor() && isVariableMutableInInitializer(function->constructorMemberInitialization(), scope->bodyStart, var->declarationId()))
    1355           8 :                 continue;
    1356             :         }
    1357         471 :         if (var->isGlobal())
    1358           0 :             continue;
    1359         471 :         if (var->isStatic())
    1360           1 :             continue;
    1361         470 :         if (var->isArray() && !var->isStlType())
    1362           0 :             continue;
    1363         470 :         if (var->isEnumType())
    1364           0 :             continue;
    1365         470 :         if (var->isVolatile())
    1366           0 :             continue;
    1367         470 :         if (var->isMaybeUnused())
    1368          16 :             continue;
    1369         454 :         if (var->nameToken()->isExpandedMacro())
    1370           0 :             continue;
    1371         454 :         if (isStructuredBindingVariable(var)) // TODO: check all bound variables
    1372           2 :             continue;
    1373         452 :         if (isVariableChanged(var, *mSettings))
    1374         363 :             continue;
    1375          89 :         const bool hasFunction = function != nullptr;
    1376          89 :         if (!hasFunction) {
    1377           7 :             const Scope* functionScope = scope;
    1378           1 :             do {
    1379           8 :                 functionScope = functionScope->nestedIn;
    1380           8 :             } while (functionScope && !(function = functionScope->function));
    1381             :         }
    1382          89 :         if (function && (Function::returnsReference(function) || Function::returnsPointer(function)) && !Function::returnsConst(function)) {
    1383          13 :             std::vector<const Token*> returns = Function::findReturns(function);
    1384          13 :             if (std::any_of(returns.cbegin(), returns.cend(), [&](const Token* retTok) {
    1385          15 :                 if (retTok->varId() == var->declarationId())
    1386           4 :                     return true;
    1387          12 :                 while (retTok && retTok->isCast())
    1388           1 :                     retTok = retTok->astOperand2();
    1389          13 :                 while (Token::simpleMatch(retTok, "."))
    1390           2 :                     retTok = retTok->astOperand2();
    1391          11 :                 if (Token::simpleMatch(retTok, "&"))
    1392           2 :                     retTok = retTok->astOperand1();
    1393          11 :                 return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken(), *mSettings);
    1394             :             }))
    1395          13 :                 continue;
    1396             :         }
    1397             :         // Skip if another non-const variable is initialized with this variable
    1398             :         {
    1399             :             //Is it the right side of an initialization of a non-const reference
    1400          76 :             bool usedInAssignment = false;
    1401        2105 :             for (const Token* tok = var->nameToken(); tok != scope->bodyEnd && tok != nullptr; tok = tok->next()) {
    1402        2040 :                 if (Token::Match(tok, "& %var% = %varid%", var->declarationId())) {
    1403           3 :                     const Variable* refvar = tok->next()->variable();
    1404           3 :                     if (refvar && !refvar->isConst() && refvar->nameToken() == tok->next()) {
    1405           2 :                         usedInAssignment = true;
    1406           2 :                         break;
    1407             :                     }
    1408             :                 }
    1409        4076 :                 if (tok->isUnaryOp("&") && Token::Match(tok, "& %varid%", var->declarationId())) {
    1410          15 :                     const Token* opTok = tok->astParent();
    1411          15 :                     int argn = -1;
    1412          29 :                     if (opTok && (opTok->isUnaryOp("!") || opTok->isComparisonOp()))
    1413           7 :                         continue;
    1414          12 :                     if (opTok && (opTok->isAssignmentOp() || opTok->isCalculation())) {
    1415           1 :                         if (opTok->isCalculation()) {
    1416           0 :                             if (opTok->astOperand1() != tok)
    1417           0 :                                 opTok = opTok->astOperand1();
    1418             :                             else
    1419           0 :                                 opTok = opTok->astOperand2();
    1420             :                         }
    1421           1 :                         if (opTok && opTok->valueType() && var->valueType() && opTok->valueType()->isConst(var->valueType()->pointer))
    1422           0 :                             continue;
    1423          11 :                     } else if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
    1424           4 :                         bool inconclusive{};
    1425           4 :                         if (var->valueType() && !isVariableChangedByFunctionCall(ftok, var->valueType()->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
    1426           4 :                             continue;
    1427             :                     }
    1428           8 :                     usedInAssignment = true;
    1429           8 :                     break;
    1430             :                 }
    1431        2023 :                 if (astIsRangeBasedForDecl(tok) && Token::Match(tok->astParent()->astOperand2(), "%varid%", var->declarationId())) {
    1432          17 :                     const Variable* refvar = tok->astParent()->astOperand1()->variable();
    1433          17 :                     if (refvar && refvar->isReference() && !refvar->isConst()) {
    1434           1 :                         usedInAssignment = true;
    1435           1 :                         break;
    1436             :                     }
    1437             :                 }
    1438             :             }
    1439          76 :             if (usedInAssignment)
    1440          11 :                 continue;
    1441             :         }
    1442             : 
    1443          65 :         constVariableError(var, hasFunction ? function : nullptr);
    1444             :     }
    1445             : }
    1446             : 
    1447         277 : static const Token* getVariableChangedStart(const Variable* p)
    1448             : {
    1449         277 :     if (p->isArgument())
    1450         109 :         return p->scope()->bodyStart;
    1451         168 :     const Token* start = p->nameToken()->next();
    1452         168 :     if (start->isSplittedVarDeclEq())
    1453          97 :         start = start->tokAt(3);
    1454         168 :     return start;
    1455             : }
    1456             : 
    1457             : namespace {
    1458             :     struct CompareVariables {
    1459       86667 :         bool operator()(const Variable* a, const Variable* b) const {
    1460       86667 :             const int fileA = a->nameToken()->fileIndex();
    1461       86667 :             const int fileB = b->nameToken()->fileIndex();
    1462       86667 :             if (fileA != fileB)
    1463           0 :                 return fileA < fileB;
    1464       86667 :             const int lineA = a->nameToken()->linenr();
    1465       86667 :             const int lineB = b->nameToken()->linenr();
    1466       86667 :             if (lineA != lineB)
    1467       80084 :                 return lineA < lineB;
    1468        6583 :             const int columnA = a->nameToken()->column();
    1469        6583 :             const int columnB = b->nameToken()->column();
    1470        6583 :             return columnA < columnB;
    1471             :         }
    1472             :     };
    1473             : }
    1474             : 
    1475        3807 : void CheckOther::checkConstPointer()
    1476             : {
    1477        3807 :     if (!mSettings->severity.isEnabled(Severity::style) &&
    1478        6128 :         !mSettings->isPremiumEnabled("constParameter") &&
    1479        2321 :         !mSettings->isPremiumEnabled("constPointer"))
    1480        2321 :         return;
    1481             : 
    1482        1486 :     logChecker("CheckOther::checkConstPointer"); // style
    1483             : 
    1484        2972 :     std::set<const Variable*, CompareVariables> pointers, nonConstPointers;
    1485      306127 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    1486      304641 :         const Variable* const var = tok->variable();
    1487      304641 :         if (!var)
    1488      300056 :             continue;
    1489       49381 :         if (!var->isLocal() && !var->isArgument())
    1490         758 :             continue;
    1491       48623 :         const Token* const nameTok = var->nameToken();
    1492       48623 :         if (tok == nameTok) {
    1493             :             // declarations of (static) pointers are (not) split up, array declarations are never split up
    1494       32096 :             if (var->isLocal() && (!var->isStatic() || Token::simpleMatch(nameTok->next(), "[")) &&
    1495       12761 :                 !astIsRangeBasedForDecl(nameTok))
    1496       12719 :                 continue;
    1497             :         }
    1498       35904 :         const ValueType* const vt = tok->valueType();
    1499       35904 :         if (!vt)
    1500         782 :             continue;
    1501       35122 :         if ((vt->pointer != 1 && !(vt->pointer == 2 && var->isArray())) || (vt->constness & 1))
    1502       26775 :             continue;
    1503        8347 :         if (var->typeStartToken()->isTemplateArg())
    1504           2 :             continue;
    1505        8345 :         if (std::find(nonConstPointers.cbegin(), nonConstPointers.cend(), var) != nonConstPointers.cend())
    1506        2762 :             continue;
    1507        5583 :         pointers.emplace(var);
    1508        5583 :         const Token* parent = tok->astParent();
    1509        5583 :         enum Deref { NONE, DEREF, MEMBER } deref = NONE;
    1510        5583 :         bool hasIncDec = false;
    1511       10054 :         if (parent && (parent->isUnaryOp("*") || (hasIncDec = parent->isIncDecOp() && parent->astParent() && parent->astParent()->isUnaryOp("*"))))
    1512         103 :             deref = DEREF;
    1513        5480 :         else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok)
    1514          80 :             deref = DEREF;
    1515        5400 :         else if (Token::Match(parent, "%op%") && Token::simpleMatch(parent->astParent(), "."))
    1516           1 :             deref = DEREF;
    1517        5399 :         else if (Token::simpleMatch(parent, "."))
    1518         114 :             deref = MEMBER;
    1519        5285 :         else if (astIsRangeBasedForDecl(tok))
    1520           7 :             continue;
    1521        5576 :         if (deref != NONE) {
    1522         298 :             const Token* gparent = parent->astParent();
    1523         298 :             if (deref == MEMBER) {
    1524         114 :                 if (!gparent)
    1525         116 :                     continue;
    1526         114 :                 if (parent->astOperand2()) {
    1527         114 :                     if (parent->astOperand2()->function() && parent->astOperand2()->function()->isConst())
    1528           4 :                         continue;
    1529         110 :                     if (mSettings->library.isFunctionConst(parent->astOperand2()))
    1530           1 :                         continue;
    1531             :                 }
    1532             :             }
    1533         446 :             if (Token::Match(gparent, "%cop%") && !gparent->isUnaryOp("&") && !gparent->isUnaryOp("*"))
    1534          53 :                 continue;
    1535         240 :             if (hasIncDec) {
    1536           7 :                 parent = gparent;
    1537           7 :                 gparent = gparent ? gparent->astParent() : nullptr;
    1538             :             }
    1539         240 :             int argn = -1;
    1540         240 :             if (Token::simpleMatch(gparent, "return")) {
    1541           6 :                 const Function* function = gparent->scope()->function;
    1542           6 :                 if (function && (!Function::returnsReference(function) || Function::returnsConst(function)))
    1543           3 :                     continue;
    1544             :             }
    1545         234 :             else if (Token::Match(gparent, "%assign%") && parent == gparent->astOperand2()) {
    1546          19 :                 bool takingRef = false, nonConstPtrAssignment = false;
    1547          19 :                 const Token *lhs = gparent->astOperand1();
    1548          19 :                 if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs && !lhs->variable()->isConst())
    1549           4 :                     takingRef = true;
    1550          21 :                 if (lhs && lhs->valueType() && lhs->valueType()->pointer && (lhs->valueType()->constness & 1) == 0 &&
    1551          40 :                     parent->valueType() && parent->valueType()->pointer)
    1552           2 :                     nonConstPtrAssignment = true;
    1553          19 :                 if (!takingRef && !nonConstPtrAssignment)
    1554          13 :                     continue;
    1555         215 :             } else if (Token::simpleMatch(gparent, "[") && gparent->astOperand2() == parent)
    1556           1 :                 continue;
    1557         220 :             else if (gparent && gparent->isCast() && gparent->valueType() &&
    1558           8 :                      ((gparent->valueType()->pointer == 0 && gparent->valueType()->reference == Reference::None) ||
    1559           4 :                       (var->valueType() && gparent->valueType()->isConst(var->valueType()->pointer))))
    1560           4 :                 continue;
    1561         210 :             else if (const Token* ftok = getTokenArgumentFunction(parent, argn)) {
    1562          69 :                 bool inconclusive{};
    1563          69 :                 if (!isVariableChangedByFunctionCall(ftok->next(), vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
    1564          37 :                     continue;
    1565             :             }
    1566             :         } else {
    1567        5278 :             int argn = -1;
    1568        5278 :             if (Token::Match(parent, "%oror%|%comp%|&&|?|!|-|<<"))
    1569         875 :                 continue;
    1570        5223 :             if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while"))
    1571          17 :                 continue;
    1572        5206 :             if (Token::simpleMatch(parent, "=") && parent->astOperand1() == tok)
    1573         630 :                 continue;
    1574        4576 :             if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
    1575        3187 :                 if (ftok->function()) {
    1576          17 :                     const bool isCastArg = parent->isCast() && !ftok->function()->getOverloadedFunctions().empty(); // assume that cast changes the called function
    1577          17 :                     if (!isCastArg) {
    1578          16 :                         const Variable* argVar = ftok->function()->getArgumentVar(argn);
    1579          16 :                         if (argVar && argVar->valueType() && argVar->valueType()->isConst(vt->pointer)) {
    1580           4 :                             bool inconclusive{};
    1581           4 :                             if (!isVariableChangedByFunctionCall(ftok, vt->pointer, var->declarationId(), *mSettings, &inconclusive) && !inconclusive)
    1582           4 :                                 continue;
    1583             :                         }
    1584             :                     }
    1585             :                 } else {
    1586        3170 :                     const auto dir = mSettings->library.getArgDirection(ftok, argn + 1);
    1587        3170 :                     if (dir == Library::ArgumentChecks::Direction::DIR_IN)
    1588         167 :                         continue;
    1589             :                 }
    1590             :             }
    1591        1389 :             else if (Token::simpleMatch(parent, "(")) {
    1592          22 :                 if (parent->isCast() && parent->valueType() && var->valueType() && parent->valueType()->isConst(var->valueType()->pointer))
    1593           2 :                     continue;
    1594             :             }
    1595             :         }
    1596        4585 :         if (tok != nameTok)
    1597        3242 :             nonConstPointers.emplace(var);
    1598             :     }
    1599        5028 :     for (const Variable *p: pointers) {
    1600        3542 :         if (p->isArgument()) {
    1601        1345 :             if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier())
    1602          24 :                 continue;
    1603        1321 :             if (p->isMaybeUnused())
    1604           8 :                 continue;
    1605             :         }
    1606        3510 :         if (std::find(nonConstPointers.cbegin(), nonConstPointers.cend(), p) == nonConstPointers.cend()) {
    1607         277 :             const Token *start = getVariableChangedStart(p);
    1608         277 :             const int indirect = p->isArray() ? p->dimensions().size() : 1;
    1609         277 :             if (isVariableChanged(start, p->scope()->bodyEnd, indirect, p->declarationId(), false, *mSettings))
    1610          31 :                 continue;
    1611         246 :             if (p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef()))
    1612          46 :                 continue;
    1613         200 :             constVariableError(p, p->isArgument() ? p->scope()->function : nullptr);
    1614             :         }
    1615             :     }
    1616             : }
    1617             : 
    1618         269 : void CheckOther::constVariableError(const Variable *var, const Function *function)
    1619             : {
    1620         269 :     if (!var) {
    1621           4 :         reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const");
    1622           4 :         reportError(nullptr, Severity::style, "constVariable",  "Variable 'x' can be declared with const");
    1623           4 :         reportError(nullptr, Severity::style, "constParameterReference", "Parameter 'x' can be declared with const");
    1624           4 :         reportError(nullptr, Severity::style, "constVariableReference", "Variable 'x' can be declared with const");
    1625           4 :         reportError(nullptr, Severity::style, "constParameterPointer", "Parameter 'x' can be declared with const");
    1626           4 :         reportError(nullptr, Severity::style, "constVariablePointer", "Variable 'x' can be declared with const");
    1627           4 :         reportError(nullptr, Severity::style, "constParameterCallback", "Parameter 'x' can be declared with const, however it seems that 'f' is a callback function.");
    1628           4 :         return;
    1629             :     }
    1630             : 
    1631         530 :     const std::string vartype(var->isArgument() ? "Parameter" : "Variable");
    1632         530 :     const std::string varname(var->name());
    1633         530 :     const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const");
    1634             : 
    1635         530 :     ErrorPath errorPath;
    1636         530 :     std::string id = "const" + vartype;
    1637         795 :     std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray;
    1638         265 :     errorPath.emplace_back(var->nameToken(), message);
    1639         265 :     if (var->isArgument() && function && function->functionPointerUsage) {
    1640           8 :         errorPath.emplace_front(function->functionPointerUsage, "You might need to cast the function pointer here");
    1641           8 :         id += "Callback";
    1642           8 :         message += ". However it seems that '" + function->name() + "' is a callback function, if '$symbol' is declared with const you might also need to cast function pointer(s).";
    1643         257 :     } else if (var->isReference()) {
    1644          66 :         id += "Reference";
    1645         191 :     } else if (var->isPointer() && !var->isArray()) {
    1646         171 :         id += "Pointer";
    1647             :     }
    1648             : 
    1649         265 :     reportError(errorPath, Severity::style, id.c_str(), message, CWE398, Certainty::normal);
    1650             : }
    1651             : 
    1652             : //---------------------------------------------------------------------------
    1653             : // Check usage of char variables..
    1654             : //---------------------------------------------------------------------------
    1655             : 
    1656        3827 : void CheckOther::checkCharVariable()
    1657             : {
    1658        3827 :     const bool warning = mSettings->severity.isEnabled(Severity::warning);
    1659        3827 :     const bool portability = mSettings->severity.isEnabled(Severity::portability);
    1660        3827 :     if (!warning && !portability)
    1661        2322 :         return;
    1662             : 
    1663        1505 :     logChecker("CheckOther::checkCharVariable"); // warning,portability
    1664             : 
    1665        1505 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1666        8688 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1667      241968 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    1668      234785 :             if (Token::Match(tok, "%var% [")) {
    1669         906 :                 if (!tok->variable())
    1670           3 :                     continue;
    1671         903 :                 if (!tok->variable()->isArray() && !tok->variable()->isPointer())
    1672         126 :                     continue;
    1673         777 :                 const Token *index = tok->next()->astOperand2();
    1674         777 :                 if (warning && tok->variable()->isArray() && astIsSignedChar(index) && index->getValueGE(0x80, *mSettings))
    1675           0 :                     signedCharArrayIndexError(tok);
    1676         777 :                 if (portability && astIsUnknownSignChar(index) && index->getValueGE(0x80, *mSettings))
    1677           3 :                     unknownSignCharArrayIndexError(tok);
    1678      233879 :             } else if (warning && Token::Match(tok, "[&|^]") && tok->isBinaryOp()) {
    1679         202 :                 bool warn = false;
    1680         202 :                 if (astIsSignedChar(tok->astOperand1())) {
    1681           0 :                     const ValueFlow::Value *v1 = tok->astOperand1()->getValueLE(-1, *mSettings);
    1682           0 :                     const ValueFlow::Value *v2 = tok->astOperand2()->getMaxValue(false);
    1683           0 :                     if (!v1)
    1684           0 :                         v1 = tok->astOperand1()->getValueGE(0x80, *mSettings);
    1685           0 :                     if (v1 && !(tok->str() == "&" && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100))
    1686           0 :                         warn = true;
    1687         202 :                 } else if (astIsSignedChar(tok->astOperand2())) {
    1688           4 :                     const ValueFlow::Value *v1 = tok->astOperand2()->getValueLE(-1, *mSettings);
    1689           4 :                     const ValueFlow::Value *v2 = tok->astOperand1()->getMaxValue(false);
    1690           4 :                     if (!v1)
    1691           0 :                         v1 = tok->astOperand2()->getValueGE(0x80, *mSettings);
    1692           4 :                     if (v1 && !(tok->str() == "&" && v2 && v2->isKnown() && v2->intvalue >= 0 && v2->intvalue < 0x100))
    1693           3 :                         warn = true;
    1694             :                 }
    1695             : 
    1696             :                 // is the result stored in a short|int|long?
    1697         202 :                 if (warn && Token::simpleMatch(tok->astParent(), "=")) {
    1698           3 :                     const Token *lhs = tok->astParent()->astOperand1();
    1699           3 :                     if (lhs && lhs->valueType() && lhs->valueType()->type >= ValueType::Type::SHORT)
    1700           2 :                         charBitOpError(tok); // This is an error..
    1701             :                 }
    1702             :             }
    1703             :         }
    1704             :     }
    1705             : }
    1706             : 
    1707           4 : void CheckOther::signedCharArrayIndexError(const Token *tok)
    1708             : {
    1709           4 :     reportError(tok,
    1710             :                 Severity::warning,
    1711             :                 "signedCharArrayIndex",
    1712             :                 "Signed 'char' type used as array index.\n"
    1713             :                 "Signed 'char' type used as array index. If the value "
    1714             :                 "can be greater than 127 there will be a buffer underflow "
    1715           8 :                 "because of sign extension.", CWE128, Certainty::normal);
    1716           4 : }
    1717             : 
    1718           7 : void CheckOther::unknownSignCharArrayIndexError(const Token *tok)
    1719             : {
    1720           7 :     reportError(tok,
    1721             :                 Severity::portability,
    1722             :                 "unknownSignCharArrayIndex",
    1723             :                 "'char' type used as array index.\n"
    1724             :                 "'char' type used as array index. Values greater than 127 will be "
    1725          14 :                 "treated depending on whether 'char' is signed or unsigned on target platform.", CWE758, Certainty::normal);
    1726           7 : }
    1727             : 
    1728           6 : void CheckOther::charBitOpError(const Token *tok)
    1729             : {
    1730           6 :     reportError(tok,
    1731             :                 Severity::warning,
    1732             :                 "charBitOp",
    1733             :                 "When using 'char' variables in bit operations, sign extension can generate unexpected results.\n"
    1734             :                 "When using 'char' variables in bit operations, sign extension can generate unexpected results. For example:\n"
    1735             :                 "    char c = 0x80;\n"
    1736             :                 "    int i = 0 | c;\n"
    1737             :                 "    if (i & 0x8000)\n"
    1738             :                 "        printf(\"not expected\");\n"
    1739          12 :                 "The \"not expected\" will be printed on the screen.", CWE398, Certainty::normal);
    1740           6 : }
    1741             : 
    1742             : //---------------------------------------------------------------------------
    1743             : // Incomplete statement..
    1744             : //---------------------------------------------------------------------------
    1745             : 
    1746          37 : static bool isType(const Token * tok, bool unknown)
    1747             : {
    1748          37 :     if (tok && (tok->isStandardType() || (!tok->isKeyword() && Token::Match(tok, "%type%")) || tok->str() == "auto"))
    1749          15 :         return true;
    1750          22 :     if (tok && tok->varId())
    1751           5 :         return false;
    1752          17 :     if (Token::simpleMatch(tok, "::"))
    1753           6 :         return isType(tok->astOperand2(), unknown);
    1754          11 :     if (Token::simpleMatch(tok, "<") && tok->link())
    1755           0 :         return true;
    1756          11 :     if (unknown && Token::Match(tok, "%name% !!("))
    1757           0 :         return true;
    1758          11 :     return false;
    1759             : }
    1760             : 
    1761          83 : static bool isVarDeclOp(const Token* tok)
    1762             : {
    1763          83 :     if (!tok)
    1764           0 :         return false;
    1765          83 :     const Token * vartok = tok->astOperand2();
    1766          83 :     if (vartok && vartok->variable() && vartok->variable()->nameToken() == vartok)
    1767          52 :         return true;
    1768          31 :     const Token * typetok = tok->astOperand1();
    1769          31 :     return isType(typetok, vartok && vartok->varId() != 0);
    1770             : }
    1771             : 
    1772       14213 : static bool isBracketAccess(const Token* tok)
    1773             : {
    1774       14213 :     if (!Token::simpleMatch(tok, "[") || !tok->astOperand1())
    1775       13926 :         return false;
    1776         287 :     tok = tok->astOperand1();
    1777         287 :     if (tok->str() == ".")
    1778           2 :         tok = tok->astOperand2();
    1779         294 :     while (Token::simpleMatch(tok, "["))
    1780           7 :         tok = tok->astOperand1();
    1781         287 :     if (!tok || !tok->variable())
    1782           1 :         return false;
    1783         286 :     return tok->variable()->nameToken() != tok;
    1784             : }
    1785             : 
    1786       23172 : static bool isConstant(const Token* tok) {
    1787       23172 :     return tok && (tok->isEnumerator() || Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"));
    1788             : }
    1789             : 
    1790       23401 : static bool isConstStatement(const Token *tok, bool isNestedBracket = false)
    1791             : {
    1792       23401 :     if (!tok)
    1793           0 :         return false;
    1794       23401 :     if (tok->isExpandedMacro())
    1795         217 :         return false;
    1796       23184 :     if (tok->varId() != 0)
    1797          57 :         return true;
    1798       23127 :     if (isConstant(tok))
    1799          73 :         return true;
    1800       23141 :     if (Token::Match(tok, "*|&|&&") &&
    1801          87 :         (Token::Match(tok->previous(), "::|.|const|volatile|restrict") || isVarDeclOp(tok)))
    1802          71 :         return false;
    1803       22983 :     if (Token::Match(tok, "<<|>>") && !astIsIntegral(tok, false))
    1804          86 :         return false;
    1805       22897 :     const Token* tok2 = tok;
    1806       54915 :     while (tok2) {
    1807       32027 :         if (Token::simpleMatch(tok2->astOperand1(), "delete"))
    1808           9 :             return false;
    1809       32018 :         tok2 = tok2->astParent();
    1810             :     }
    1811       22888 :     if (Token::Match(tok, "&&|%oror%"))
    1812           2 :         return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
    1813       22886 :     if (Token::Match(tok, "!|~|%cop%") && (tok->astOperand1() || tok->astOperand2()))
    1814          55 :         return true;
    1815       22831 :     if (Token::simpleMatch(tok->previous(), "sizeof ("))
    1816           0 :         return true;
    1817       22831 :     if (isCPPCast(tok)) {
    1818           7 :         if (Token::simpleMatch(tok->astOperand1(), "dynamic_cast") && Token::simpleMatch(tok->astOperand1()->linkAt(1)->previous(), "& >"))
    1819           1 :             return false;
    1820           6 :         return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2());
    1821             :     }
    1822       22824 :     if (tok->isCast() && tok->next() && tok->next()->isStandardType())
    1823        8575 :         return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1());
    1824       14249 :     if (Token::simpleMatch(tok, "."))
    1825           7 :         return isConstStatement(tok->astOperand2());
    1826       14242 :     if (Token::simpleMatch(tok, ",")) {
    1827          16 :         if (tok->astParent()) // warn about const statement on rhs at the top level
    1828           6 :             return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2());
    1829             : 
    1830          10 :         const Token* lml = previousBeforeAstLeftmostLeaf(tok); // don't warn about matrix/vector assignment (e.g. Eigen)
    1831          10 :         if (lml)
    1832          10 :             lml = lml->next();
    1833          10 :         const Token* stream = lml;
    1834          23 :         while (stream && Token::Match(stream->astParent(), ".|[|(|*"))
    1835          13 :             stream = stream->astParent();
    1836          10 :         return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2());
    1837             :     }
    1838       14226 :     if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) // ternary operator
    1839          13 :         return isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand1()) && isConstStatement(tok->astOperand2()->astOperand2());
    1840       14213 :     if (isBracketAccess(tok) && isWithoutSideEffects(tok->astOperand1(), /*checkArrayAccess*/ true, /*checkReference*/ false)) {
    1841          21 :         const bool isChained = succeeds(tok->astParent(), tok);
    1842          21 :         if (Token::simpleMatch(tok->astParent(), "[")) {
    1843          11 :             if (isChained)
    1844           7 :                 return isConstStatement(tok->astOperand2()) && isConstStatement(tok->astParent());
    1845           4 :             return isNestedBracket && isConstStatement(tok->astOperand2());
    1846             :         }
    1847          10 :         return isConstStatement(tok->astOperand2(), /*isNestedBracket*/ !isChained);
    1848             :     }
    1849       14192 :     return false;
    1850             : }
    1851             : 
    1852         122 : static bool isVoidStmt(const Token *tok)
    1853             : {
    1854         122 :     if (Token::simpleMatch(tok, "( void"))
    1855          32 :         return true;
    1856          90 :     if (isCPPCast(tok) && tok->astOperand1() && Token::Match(tok->astOperand1()->next(), "< void *| >"))
    1857           2 :         return true;
    1858          88 :     const Token *tok2 = tok;
    1859         211 :     while (tok2->astOperand1())
    1860         123 :         tok2 = tok2->astOperand1();
    1861          88 :     if (Token::simpleMatch(tok2->previous(), ")") && Token::simpleMatch(tok2->previous()->link(), "( void"))
    1862           1 :         return true;
    1863          87 :     if (Token::simpleMatch(tok2, "( void"))
    1864           0 :         return true;
    1865          87 :     return Token::Match(tok2->previous(), "delete|throw|return");
    1866             : }
    1867             : 
    1868      243238 : static bool isConstTop(const Token *tok)
    1869             : {
    1870      243238 :     if (!tok)
    1871           0 :         return false;
    1872      243238 :     if (!tok->astParent())
    1873      138489 :         return true;
    1874      104749 :     if (Token::simpleMatch(tok->astParent(), ";") &&
    1875      104749 :         Token::Match(tok->astTop()->previous(), "for|if (") && Token::simpleMatch(tok->astTop()->astOperand2(), ";")) {
    1876         475 :         if (Token::simpleMatch(tok->astParent()->astParent(), ";"))
    1877         226 :             return tok->astParent()->astOperand2() == tok;
    1878         249 :         return tok->astParent()->astOperand1() == tok;
    1879             :     }
    1880      104274 :     if (Token::simpleMatch(tok, "[")) {
    1881         776 :         const Token* bracTok = tok;
    1882         803 :         while (Token::simpleMatch(bracTok->astParent(), "["))
    1883          27 :             bracTok = bracTok->astParent();
    1884         776 :         if (!bracTok->astParent())
    1885          11 :             return true;
    1886             :     }
    1887      104263 :     if (tok->str() == "," && tok->astParent()->isAssignmentOp())
    1888           1 :         return true;
    1889      104262 :     return false;
    1890             : }
    1891             : 
    1892        3901 : void CheckOther::checkIncompleteStatement()
    1893             : {
    1894        3901 :     if (!mSettings->severity.isEnabled(Severity::warning))
    1895        2322 :         return;
    1896             : 
    1897        1579 :     logChecker("CheckOther::checkIncompleteStatement"); // warning
    1898             : 
    1899      308960 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    1900      307381 :         const Scope *scope = tok->scope();
    1901      307381 :         if (scope && !scope->isExecutable())
    1902       64143 :             continue;
    1903      243238 :         if (!isConstTop(tok))
    1904      104512 :             continue;
    1905      138726 :         if (tok->str() == "," && Token::simpleMatch(tok->astTop()->previous(), "for ("))
    1906           1 :             continue;
    1907             : 
    1908             :         // Do not warn for statement when both lhs and rhs has side effects:
    1909             :         //   dostuff() || x=213;
    1910      138725 :         if (Token::Match(tok, "%oror%|&&")) {
    1911           4 :             bool warn = false;
    1912           4 :             visitAstNodes(tok, [&warn](const Token *child) {
    1913           9 :                 if (Token::Match(child, "%oror%|&&"))
    1914           4 :                     return ChildrenToVisit::op1_and_op2;
    1915           5 :                 if (child->isAssignmentOp())
    1916           1 :                     return ChildrenToVisit::none;
    1917           4 :                 if (child->tokType() == Token::Type::eIncDecOp)
    1918           0 :                     return ChildrenToVisit::none;
    1919           4 :                 if (Token::Match(child->previous(), "%name% ("))
    1920           1 :                     return ChildrenToVisit::none;
    1921           3 :                 warn = true;
    1922           3 :                 return ChildrenToVisit::done;
    1923             :             });
    1924           4 :             if (!warn)
    1925           1 :                 continue;
    1926             :         }
    1927             : 
    1928      138724 :         const Token *rtok = nextAfterAstRightmostLeaf(tok);
    1929      277224 :         if (!Token::simpleMatch(tok->astParent(), ";") && !Token::simpleMatch(rtok, ";") &&
    1930      124780 :             !Token::Match(tok->previous(), ";|}|{ %any% ;") &&
    1931      124356 :             !(tok->isCpp() && tok->isCast() && !tok->astParent()) &&
    1932      124350 :             !Token::simpleMatch(tok->tokAt(-2), "for (") &&
    1933      401159 :             !Token::Match(tok->tokAt(-1), "%var% [") &&
    1934      123935 :             !(tok->str() == "," && tok->astParent() && tok->astParent()->isAssignmentOp()))
    1935      123934 :             continue;
    1936             :         // Skip statement expressions
    1937       14790 :         if (Token::simpleMatch(rtok, "; } )"))
    1938          42 :             continue;
    1939       14748 :         if (!isConstStatement(tok))
    1940       14626 :             continue;
    1941         122 :         if (isVoidStmt(tok))
    1942          35 :             continue;
    1943          87 :         if (tok->isCpp() && tok->str() == "&" && !(tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isIntegral()))
    1944             :             // Possible archive
    1945           1 :             continue;
    1946          86 :         const bool inconclusive = tok->isConstOp();
    1947          86 :         if (mSettings->certainty.isEnabled(Certainty::inconclusive) || !inconclusive)
    1948          83 :             constStatementError(tok, tok->isNumber() ? "numeric" : "string", inconclusive);
    1949             :     }
    1950             : }
    1951             : 
    1952          87 : void CheckOther::constStatementError(const Token *tok, const std::string &type, bool inconclusive)
    1953             : {
    1954          87 :     const Token *valueTok = tok;
    1955          99 :     while (valueTok && valueTok->isCast())
    1956          12 :         valueTok = valueTok->astOperand2() ? valueTok->astOperand2() : valueTok->astOperand1();
    1957             : 
    1958          87 :     std::string msg;
    1959          87 :     if (Token::simpleMatch(tok, "=="))
    1960           8 :         msg = "Found suspicious equality comparison. Did you intend to assign a value instead?";
    1961          79 :     else if (Token::Match(tok, ",|!|~|%cop%"))
    1962          31 :         msg = "Found suspicious operator '" + tok->str() + "', result is not used.";
    1963          48 :     else if (Token::Match(tok, "%var%"))
    1964           3 :         msg = "Unused variable value '" + tok->str() + "'";
    1965          45 :     else if (isConstant(valueTok)) {
    1966          19 :         std::string typeStr("string");
    1967          19 :         if (valueTok->isNumber())
    1968           9 :             typeStr = "numeric";
    1969          10 :         else if (valueTok->isBoolean())
    1970           2 :             typeStr = "bool";
    1971           8 :         else if (valueTok->tokType() == Token::eChar)
    1972           2 :             typeStr = "character";
    1973           6 :         else if (isNullOperand(valueTok))
    1974           2 :             typeStr = "NULL";
    1975           4 :         else if (valueTok->isEnumerator())
    1976           1 :             typeStr = "enumerator";
    1977          19 :         msg = "Redundant code: Found a statement that begins with " + typeStr + " constant.";
    1978             :     }
    1979          26 :     else if (!tok)
    1980           4 :         msg = "Redundant code: Found a statement that begins with " + type + " constant.";
    1981          22 :     else if (tok->isCast() && tok->tokType() == Token::Type::eExtendedOp) {
    1982           7 :         msg = "Redundant code: Found unused cast ";
    1983           7 :         msg += valueTok ? "of expression '" + valueTok->expressionString() + "'." : "expression.";
    1984             :     }
    1985          15 :     else if (tok->str() == "?" && tok->tokType() == Token::Type::eExtendedOp)
    1986           1 :         msg = "Redundant code: Found unused result of ternary operator.";
    1987          14 :     else if (tok->str() == "." && tok->tokType() == Token::Type::eOther)
    1988           6 :         msg = "Redundant code: Found unused member access.";
    1989           8 :     else if (tok->str() == "[" && tok->tokType() == Token::Type::eExtendedOp)
    1990           8 :         msg = "Redundant code: Found unused array access.";
    1991           0 :     else if (mSettings->debugwarnings) {
    1992           0 :         reportError(tok, Severity::debug, "debug", "constStatementError not handled.");
    1993           0 :         return;
    1994             :     }
    1995          87 :     reportError(tok, Severity::warning, "constStatement", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
    1996             : }
    1997             : 
    1998             : //---------------------------------------------------------------------------
    1999             : // Detect division by zero.
    2000             : //---------------------------------------------------------------------------
    2001        3807 : void CheckOther::checkZeroDivision()
    2002             : {
    2003        3807 :     logChecker("CheckOther::checkZeroDivision");
    2004             : 
    2005      358001 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    2006      354194 :         if (!tok->astOperand2() || !tok->astOperand1())
    2007      304095 :             continue;
    2008       50099 :         if (tok->str() != "%" && tok->str() != "/" && tok->str() != "%=" && tok->str() != "/=")
    2009       49812 :             continue;
    2010         287 :         if (!tok->valueType() || !tok->valueType()->isIntegral())
    2011          39 :             continue;
    2012         248 :         if (tok->scope() && tok->scope()->type == Scope::eEnum) // don't warn for compile-time error
    2013           1 :             continue;
    2014             : 
    2015             :         // Value flow..
    2016         247 :         const ValueFlow::Value *value = tok->astOperand2()->getValue(0LL);
    2017         247 :         if (value && mSettings->isEnabled(value, false))
    2018         156 :             zerodivError(tok, value);
    2019             :     }
    2020        3807 : }
    2021             : 
    2022         160 : void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value)
    2023             : {
    2024         160 :     if (!tok && !value) {
    2025           4 :         reportError(tok, Severity::error, "zerodiv", "Division by zero.", CWE369, Certainty::normal);
    2026           4 :         reportError(tok, Severity::warning, "zerodivcond", ValueFlow::eitherTheConditionIsRedundant(nullptr) + " or there is division by zero.", CWE369, Certainty::normal);
    2027           4 :         return;
    2028             :     }
    2029             : 
    2030         468 :     const ErrorPath errorPath = getErrorPath(tok, value, "Division by zero");
    2031             : 
    2032         156 :     std::ostringstream errmsg;
    2033         156 :     if (value->condition) {
    2034           7 :         const int line = tok ? tok->linenr() : 0;
    2035          14 :         errmsg << ValueFlow::eitherTheConditionIsRedundant(value->condition)
    2036           7 :                << " or there is division by zero at line " << line << ".";
    2037             :     } else
    2038         149 :         errmsg << "Division by zero.";
    2039             : 
    2040         468 :     reportError(errorPath,
    2041         156 :                 value->errorSeverity() ? Severity::error : Severity::warning,
    2042         156 :                 value->condition ? "zerodivcond" : "zerodiv",
    2043         468 :                 errmsg.str(), CWE369, value->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
    2044             : }
    2045             : 
    2046             : //---------------------------------------------------------------------------
    2047             : // Check for NaN (not-a-number) in an arithmetic expression, e.g.
    2048             : // double d = 1.0 / 0.0 + 100.0;
    2049             : //---------------------------------------------------------------------------
    2050             : 
    2051        3806 : void CheckOther::checkNanInArithmeticExpression()
    2052             : {
    2053        3806 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("nanInArithmeticExpression"))
    2054        2321 :         return;
    2055        1486 :     logChecker("CheckOther::checkNanInArithmeticExpression"); // style
    2056      306127 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    2057      304641 :         if (tok->str() != "/")
    2058      304414 :             continue;
    2059         227 :         if (!Token::Match(tok->astParent(), "[+-]"))
    2060         223 :             continue;
    2061           4 :         if (Token::simpleMatch(tok->astOperand2(), "0.0"))
    2062           4 :             nanInArithmeticExpressionError(tok);
    2063             :     }
    2064             : }
    2065             : 
    2066           8 : void CheckOther::nanInArithmeticExpressionError(const Token *tok)
    2067             : {
    2068           8 :     reportError(tok, Severity::style, "nanInArithmeticExpression",
    2069             :                 "Using NaN/Inf in a computation.\n"
    2070             :                 "Using NaN/Inf in a computation. "
    2071          16 :                 "Although nothing bad really happens, it is suspicious.", CWE369, Certainty::normal);
    2072           8 : }
    2073             : 
    2074             : //---------------------------------------------------------------------------
    2075             : // Creating instance of classes which are destroyed immediately
    2076             : //---------------------------------------------------------------------------
    2077        3807 : void CheckOther::checkMisusedScopedObject()
    2078             : {
    2079             :     // Skip this check for .c files
    2080        3807 :     if (mTokenizer->isC())
    2081        2425 :         return;
    2082             : 
    2083        3702 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedScopedObject"))
    2084        2320 :         return;
    2085             : 
    2086        1382 :     logChecker("CheckOther::checkMisusedScopedObject"); // style,c++
    2087             : 
    2088      132705 :     auto getConstructorTok = [](const Token* tok, std::string& typeStr) -> const Token* {
    2089      132705 :         if (!Token::Match(tok, "[;{}] %name%") || tok->next()->isKeyword())
    2090      121874 :             return nullptr;
    2091       10831 :         tok = tok->next();
    2092       10831 :         typeStr.clear();
    2093       11512 :         while (Token::Match(tok, "%name% ::")) {
    2094         681 :             typeStr += tok->str();
    2095         681 :             typeStr += "::";
    2096         681 :             tok = tok->tokAt(2);
    2097             :         }
    2098       10831 :         typeStr += tok->str();
    2099       10831 :         const Token* endTok = tok;
    2100       10831 :         if (Token::Match(endTok, "%name% <"))
    2101         289 :             endTok = endTok->linkAt(1);
    2102       12336 :         if (Token::Match(endTok, "%name%|> (|{") && Token::Match(endTok->linkAt(1), ")|} ;") &&
    2103        1505 :             !Token::simpleMatch(endTok->next()->astParent(), ";")) { // for loop condition
    2104        1504 :             return tok;
    2105             :         }
    2106        9327 :         return nullptr;
    2107             :     };
    2108             : 
    2109        1487 :     auto isLibraryConstructor = [&](const Token* tok, const std::string& typeStr) -> bool {
    2110        1487 :         const Library::TypeCheck typeCheck = mSettings->library.getTypeCheck("unusedvar", typeStr);
    2111        1487 :         if (typeCheck == Library::TypeCheck::check || typeCheck == Library::TypeCheck::checkFiniteLifetime)
    2112           5 :             return true;
    2113        1482 :         return mSettings->library.detectContainerOrIterator(tok);
    2114        1382 :     };
    2115             : 
    2116        1382 :     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
    2117        2764 :     std::string typeStr;
    2118        5917 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    2119      137240 :         for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
    2120      132705 :             const Token* ctorTok = getConstructorTok(tok, typeStr);
    2121      134209 :             if (ctorTok && (((ctorTok->type() || ctorTok->isStandardType() || (ctorTok->function() && ctorTok->function()->isConstructor())) // TODO: The rhs of || should be removed; It is a workaround for a symboldatabase bug
    2122          18 :                              && (!ctorTok->function() || ctorTok->function()->isConstructor()) // // is not a function on this scope or is function in this scope and it's a ctor
    2123        1504 :                              && ctorTok->str() != "void") || isLibraryConstructor(tok->next(), typeStr))) {
    2124          24 :                 const Token* parTok = ctorTok->next();
    2125          24 :                 if (Token::simpleMatch(parTok, "<") && parTok->link())
    2126           4 :                     parTok = parTok->link()->next();
    2127          24 :                 if (const Token* arg = parTok->astOperand2()) {
    2128          19 :                     if (!isConstStatement(arg))
    2129           2 :                         continue;
    2130          17 :                     if (parTok->str() == "(") {
    2131          13 :                         if (arg->varId() && !(arg->variable() && arg->variable()->nameToken() != arg))
    2132           1 :                             continue;
    2133          12 :                         const Token* rml = nextAfterAstRightmostLeaf(arg);
    2134          12 :                         if (rml && rml->previous() && rml->previous()->varId())
    2135           2 :                             continue;
    2136             :                     }
    2137             :                 }
    2138          19 :                 tok = tok->next();
    2139          19 :                 misusedScopeObjectError(ctorTok, typeStr);
    2140          19 :                 tok = tok->next();
    2141             :             }
    2142      132700 :             if (tok->isAssignmentOp() && Token::simpleMatch(tok->astOperand1(), "(") && tok->astOperand1()->astOperand1()) {
    2143           9 :                 if (const Function* ftok = tok->astOperand1()->astOperand1()->function()) {
    2144           3 :                     if (ftok->retType && Token::Match(ftok->retType->classDef, "class|struct|union") && !Function::returnsReference(ftok, /*unknown*/ false, /*includeRValueRef*/ true))
    2145           1 :                         misusedScopeObjectError(tok->next(), ftok->retType->name(), /*isAssignment*/ true);
    2146             :                 }
    2147             :             }
    2148             :         }
    2149             :     }
    2150             : }
    2151             : 
    2152          24 : void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment)
    2153             : {
    2154          24 :     std::string msg = "Instance of '$symbol' object is destroyed immediately";
    2155          24 :     msg += isAssignment ? ", assignment has no effect." : ".";
    2156          24 :     reportError(tok, Severity::style,
    2157             :                 "unusedScopedObject",
    2158          48 :                 "$symbol:" + varname + "\n" +
    2159          48 :                 msg, CWE563, Certainty::normal);
    2160          24 : }
    2161             : 
    2162          36 : static const Token * getSingleExpressionInBlock(const Token * tok)
    2163             : {
    2164          36 :     if (!tok)
    2165           0 :         return nullptr;
    2166          36 :     const Token * top = tok->astTop();
    2167          36 :     if (!top)
    2168           0 :         return nullptr;
    2169          36 :     const Token * nextExpression = nextAfterAstRightmostLeaf(top);
    2170          36 :     if (!Token::simpleMatch(nextExpression, "; }"))
    2171          25 :         return nullptr;
    2172          11 :     return top;
    2173             : }
    2174             : 
    2175             : //-----------------------------------------------------------------------------
    2176             : // check for duplicate code in if and else branches
    2177             : // if (a) { b = true; } else { b = true; }
    2178             : //-----------------------------------------------------------------------------
    2179        3807 : void CheckOther::checkDuplicateBranch()
    2180             : {
    2181             :     // This is inconclusive since in practice most warnings are noise:
    2182             :     // * There can be unfixed low-priority todos. The code is fine as it
    2183             :     //   is but it could be possible to enhance it. Writing a warning
    2184             :     //   here is noise since the code is fine (see cppcheck, abiword, ..)
    2185             :     // * There can be overspecified code so some conditions can't be true
    2186             :     //   and their conditional code is a duplicate of the condition that
    2187             :     //   is always true just in case it would be false. See for instance
    2188             :     //   abiword.
    2189        3807 :     if (!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
    2190        2420 :         return;
    2191             : 
    2192        1387 :     logChecker("CheckOther::checkDuplicateBranch"); // style,inconclusive
    2193             : 
    2194        1387 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2195             : 
    2196       11637 :     for (const Scope & scope : symbolDatabase->scopeList) {
    2197       10250 :         if (scope.type != Scope::eIf)
    2198        9324 :             continue;
    2199             : 
    2200             :         // check all the code in the function for if (..) else
    2201         926 :         if (Token::simpleMatch(scope.bodyEnd, "} else {")) {
    2202             :             // Make sure there are no macros (different macros might be expanded
    2203             :             // to the same code)
    2204          39 :             bool macro = false;
    2205         748 :             for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd->linkAt(2); tok = tok->next()) {
    2206         711 :                 if (tok->isExpandedMacro()) {
    2207           2 :                     macro = true;
    2208           2 :                     break;
    2209             :                 }
    2210             :             }
    2211          39 :             if (macro)
    2212          35 :                 continue;
    2213             : 
    2214          37 :             const Token * const tokIf = scope.bodyStart->next();
    2215          37 :             const Token * const tokElse = scope.bodyEnd->tokAt(3);
    2216             : 
    2217             :             // compare first tok before stringifying the whole blocks
    2218          37 :             const std::string tokIfStr = tokIf->stringify(false, true, false);
    2219          37 :             if (tokIfStr.empty())
    2220           0 :                 continue;
    2221             : 
    2222          37 :             const std::string tokElseStr = tokElse->stringify(false, true, false);
    2223             : 
    2224          37 :             if (tokIfStr == tokElseStr) {
    2225             :                 // save if branch code
    2226          15 :                 const std::string branch1 = tokIf->stringifyList(scope.bodyEnd);
    2227             : 
    2228          15 :                 if (branch1.empty())
    2229           1 :                     continue;
    2230             : 
    2231             :                 // save else branch code
    2232          14 :                 const std::string branch2 = tokElse->stringifyList(scope.bodyEnd->linkAt(2));
    2233             : 
    2234             :                 // check for duplicates
    2235          14 :                 if (branch1 == branch2) {
    2236           7 :                     duplicateBranchError(scope.classDef, scope.bodyEnd->next(), ErrorPath{});
    2237           7 :                     continue;
    2238             :                 }
    2239             :             }
    2240             : 
    2241             :             // check for duplicates using isSameExpression
    2242          29 :             const Token * branchTop1 = getSingleExpressionInBlock(tokIf);
    2243          29 :             if (!branchTop1)
    2244          22 :                 continue;
    2245           7 :             const Token * branchTop2 = getSingleExpressionInBlock(tokElse);
    2246           7 :             if (!branchTop2)
    2247           3 :                 continue;
    2248           4 :             if (branchTop1->str() != branchTop2->str())
    2249           0 :                 continue;
    2250           8 :             ErrorPath errorPath;
    2251           7 :             if (isSameExpression(false, branchTop1->astOperand1(), branchTop2->astOperand1(), *mSettings, true, true, &errorPath) &&
    2252           3 :                 isSameExpression(false, branchTop1->astOperand2(), branchTop2->astOperand2(), *mSettings, true, true, &errorPath))
    2253           1 :                 duplicateBranchError(scope.classDef, scope.bodyEnd->next(), std::move(errorPath));
    2254             :         }
    2255             :     }
    2256             : }
    2257             : 
    2258          12 : void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors)
    2259             : {
    2260          12 :     errors.emplace_back(tok2, "");
    2261          12 :     errors.emplace_back(tok1, "");
    2262             : 
    2263          12 :     reportError(errors, Severity::style, "duplicateBranch", "Found duplicate branches for 'if' and 'else'.\n"
    2264             :                 "Finding the same code in an 'if' and related 'else' branch is suspicious and "
    2265             :                 "might indicate a cut and paste or logic error. Please examine this code "
    2266          24 :                 "carefully to determine if it is correct.", CWE398, Certainty::inconclusive);
    2267          12 : }
    2268             : 
    2269             : 
    2270             : //-----------------------------------------------------------------------------
    2271             : // Check for a free() of an invalid address
    2272             : // char* p = malloc(100);
    2273             : // free(p + 10);
    2274             : //-----------------------------------------------------------------------------
    2275        3807 : void CheckOther::checkInvalidFree()
    2276             : {
    2277        7614 :     std::map<int, bool> inconclusive;
    2278        7614 :     std::map<int, std::string> allocation;
    2279             : 
    2280        3806 :     logChecker("CheckOther::checkInvalidFree");
    2281             : 
    2282        3807 :     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
    2283        3807 :     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
    2284       13279 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    2285      272441 :         for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
    2286             : 
    2287             :             // Keep track of which variables were assigned addresses to newly-allocated memory
    2288      525922 :             if ((tok->isCpp() && Token::Match(tok, "%var% = new")) ||
    2289      262952 :                 (Token::Match(tok, "%var% = %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)))) {
    2290         399 :                 allocation.insert(std::make_pair(tok->varId(), tok->strAt(2)));
    2291         399 :                 inconclusive.insert(std::make_pair(tok->varId(), false));
    2292             :             }
    2293             : 
    2294             :             // If a previously-allocated pointer is incremented or decremented, any subsequent
    2295             :             // free involving pointer arithmetic may or may not be invalid, so we should only
    2296             :             // report an inconclusive result.
    2297      262584 :             else if (Token::Match(tok, "%var% = %name% +|-") &&
    2298      262584 :                      tok->varId() == tok->tokAt(2)->varId() &&
    2299      262573 :                      allocation.find(tok->varId()) != allocation.end()) {
    2300           0 :                 if (printInconclusive)
    2301           0 :                     inconclusive[tok->varId()] = true;
    2302             :                 else {
    2303           0 :                     allocation.erase(tok->varId());
    2304           0 :                     inconclusive.erase(tok->varId());
    2305             :                 }
    2306             :             }
    2307             : 
    2308             :             // If a previously-allocated pointer is assigned a completely new value,
    2309             :             // we can't know if any subsequent free() on that pointer is valid or not.
    2310      262571 :             else if (Token::Match(tok, "%var% =")) {
    2311        4164 :                 allocation.erase(tok->varId());
    2312        4164 :                 inconclusive.erase(tok->varId());
    2313             :             }
    2314             : 
    2315             :             // If a variable that was previously assigned a newly-allocated memory location is
    2316             :             // added or subtracted from when used to free the memory, report an error.
    2317      258459 :             else if ((Token::Match(tok, "%name% ( %any% +|-") && mSettings->library.getDeallocFuncInfo(tok)) ||
    2318      516855 :                      Token::Match(tok, "delete [ ] ( %any% +|-") ||
    2319      258399 :                      Token::Match(tok, "delete %any% +|- %any%")) {
    2320             : 
    2321          21 :                 const int varIndex = tok->strAt(1) == "(" ? 2 :
    2322           8 :                                      tok->strAt(3) == "(" ? 4 : 1;
    2323          13 :                 const int var1 = tok->tokAt(varIndex)->varId();
    2324          13 :                 const int var2 = tok->tokAt(varIndex + 2)->varId();
    2325          13 :                 const std::map<int, bool>::const_iterator alloc1 = inconclusive.find(var1);
    2326          13 :                 const std::map<int, bool>::const_iterator alloc2 = inconclusive.find(var2);
    2327          13 :                 if (alloc1 != inconclusive.end()) {
    2328           7 :                     invalidFreeError(tok, allocation[var1], alloc1->second);
    2329           6 :                 } else if (alloc2 != inconclusive.end()) {
    2330           1 :                     invalidFreeError(tok, allocation[var2], alloc2->second);
    2331             :                 }
    2332             :             }
    2333             : 
    2334             :             // If the previously-allocated variable is passed in to another function
    2335             :             // as a parameter, it might be modified, so we shouldn't report an error
    2336             :             // if it is later used to free memory
    2337      258393 :             else if (Token::Match(tok, "%name% (") && !mSettings->library.isFunctionConst(tok->str(), true)) {
    2338       13221 :                 const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1));
    2339       32116 :                 while (tok2 != nullptr) {
    2340       18895 :                     allocation.erase(tok->varId());
    2341       18895 :                     inconclusive.erase(tok2->varId());
    2342       18895 :                     tok2 = Token::findmatch(tok2->next(), "%var%", tok->linkAt(1));
    2343             :                 }
    2344             :             }
    2345             :         }
    2346             :     }
    2347        3807 : }
    2348             : 
    2349          12 : void CheckOther::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive)
    2350             : {
    2351          24 :     std::string alloc = allocation;
    2352          12 :     if (alloc != "new")
    2353           8 :         alloc += "()";
    2354          12 :     std::string deallocated = (alloc == "new") ? "deleted" : "freed";
    2355          12 :     reportError(tok, Severity::error, "invalidFree", "Mismatching address is " + deallocated + ". The address you get from " + alloc + " must be " + deallocated + " without offset.", CWE(0U), inconclusive ? Certainty::inconclusive : Certainty::normal);
    2356          12 : }
    2357             : 
    2358             : 
    2359             : //---------------------------------------------------------------------------
    2360             : // check for the same expression on both sides of an operator
    2361             : // (x == x), (x && x), (x || x)
    2362             : // (x.y == x.y), (x.y && x.y), (x.y || x.y)
    2363             : //---------------------------------------------------------------------------
    2364             : 
    2365             : namespace {
    2366        7474 :     bool notconst(const Function* func)
    2367             :     {
    2368        7474 :         return !func->isConst();
    2369             :     }
    2370             : 
    2371        1486 :     void getConstFunctions(const SymbolDatabase *symbolDatabase, std::list<const Function*> &constFunctions)
    2372             :     {
    2373       12051 :         for (const Scope &scope : symbolDatabase->scopeList) {
    2374             :             // only add const functions that do not have a non-const overloaded version
    2375             :             // since it is pretty much impossible to tell which is being called.
    2376             :             using StringFunctionMap = std::map<std::string, std::list<const Function*>>;
    2377       21130 :             StringFunctionMap functionsByName;
    2378       18098 :             for (const Function &func : scope.functionList) {
    2379        7533 :                 functionsByName[func.tokenDef->str()].push_back(&func);
    2380             :             }
    2381       18037 :             for (std::pair<const std::string, std::list<const Function*>>& it : functionsByName) {
    2382        7472 :                 const std::list<const Function*>::const_iterator nc = std::find_if(it.second.cbegin(), it.second.cend(), notconst);
    2383        7472 :                 if (nc == it.second.cend()) {
    2384             :                     // ok to add all of them
    2385          88 :                     constFunctions.splice(constFunctions.end(), it.second);
    2386             :                 }
    2387             :             }
    2388             :         }
    2389        1486 :     }
    2390             : }
    2391             : 
    2392        3807 : void CheckOther::checkDuplicateExpression()
    2393             : {
    2394             :     {
    2395        3807 :         const bool styleEnabled = mSettings->severity.isEnabled(Severity::style);
    2396        3807 :         const bool premiumEnabled = mSettings->isPremiumEnabled("oppositeExpression") ||
    2397        3807 :                                     mSettings->isPremiumEnabled("duplicateExpression") ||
    2398        3807 :                                     mSettings->isPremiumEnabled("duplicateAssignExpression") ||
    2399        3807 :                                     mSettings->isPremiumEnabled("duplicateExpressionTernary") ||
    2400        3807 :                                     mSettings->isPremiumEnabled("duplicateValueTernary") ||
    2401       11421 :                                     mSettings->isPremiumEnabled("selfAssignment") ||
    2402        3807 :                                     mSettings->isPremiumEnabled("knownConditionTrueFalse");
    2403             : 
    2404        3807 :         if (!styleEnabled && !premiumEnabled)
    2405        2321 :             return;
    2406             :     }
    2407             : 
    2408        1486 :     logChecker("CheckOther::checkDuplicateExpression"); // style,warning
    2409             : 
    2410             :     // Parse all executing scopes..
    2411        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2412             : 
    2413        2972 :     std::list<const Function*> constFunctions;
    2414        1486 :     getConstFunctions(symbolDatabase, constFunctions);
    2415             : 
    2416        8649 :     for (const Scope *scope : symbolDatabase->functionScopes) {
    2417      241689 :         for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    2418      234526 :             if (tok->str() == "=" && Token::Match(tok->astOperand1(), "%var%")) {
    2419        2513 :                 const Token * endStatement = Token::findsimplematch(tok, ";");
    2420        2513 :                 if (Token::Match(endStatement, "; %type% %var% ;")) {
    2421         205 :                     endStatement = endStatement->tokAt(4);
    2422             :                 }
    2423        2513 :                 if (Token::Match(endStatement, "%var% %assign%")) {
    2424         167 :                     const Token * nextAssign = endStatement->tokAt(1);
    2425         167 :                     const Token * var1 = tok->astOperand1();
    2426         167 :                     const Token * var2 = nextAssign->astOperand1();
    2427         167 :                     if (var1 && var2 &&
    2428         167 :                         Token::Match(var1->previous(), ";|{|} %var%") &&
    2429         328 :                         Token::Match(var2->previous(), ";|{|} %var%") &&
    2430         460 :                         var2->valueType() && var1->valueType() &&
    2431         148 :                         var2->valueType()->originalTypeName == var1->valueType()->originalTypeName &&
    2432         133 :                         var2->valueType()->pointer == var1->valueType()->pointer &&
    2433         256 :                         var2->valueType()->constness == var1->valueType()->constness &&
    2434         256 :                         var2->varId() != var1->varId() && (
    2435         241 :                             tok->astOperand2()->isArithmeticalOp() ||
    2436         113 :                             tok->astOperand2()->str() == "." ||
    2437         104 :                             Token::Match(tok->astOperand2()->previous(), "%name% (")
    2438          65 :                             ) &&
    2439          65 :                         tok->next()->tokType() != Token::eType &&
    2440          64 :                         isSameExpression(true, tok->next(), nextAssign->next(), *mSettings, true, false) &&
    2441         358 :                         isSameExpression(true, tok->astOperand2(), nextAssign->astOperand2(), *mSettings, true, false) &&
    2442         191 :                         tok->astOperand2()->expressionString() == nextAssign->astOperand2()->expressionString()) {
    2443          23 :                         bool differentDomain = false;
    2444          23 :                         const Scope * varScope = var1->scope() ? var1->scope() : scope;
    2445         114 :                         for (const Token *assignTok = Token::findsimplematch(var2, ";"); assignTok && assignTok != varScope->bodyEnd; assignTok = assignTok->next()) {
    2446          97 :                             if (!Token::Match(assignTok, "%assign%|%comp%"))
    2447          91 :                                 continue;
    2448           6 :                             if (!assignTok->astOperand1())
    2449           0 :                                 continue;
    2450           6 :                             if (!assignTok->astOperand2())
    2451           0 :                                 continue;
    2452             : 
    2453           9 :                             if (assignTok->astOperand1()->varId() != var1->varId() &&
    2454           9 :                                 assignTok->astOperand1()->varId() != var2->varId() &&
    2455           0 :                                 !isSameExpression(true,
    2456             :                                                   tok->astOperand2(),
    2457             :                                                   assignTok->astOperand1(),
    2458           0 :                                                   *mSettings,
    2459             :                                                   true,
    2460             :                                                   true))
    2461           0 :                                 continue;
    2462          10 :                             if (assignTok->astOperand2()->varId() != var1->varId() &&
    2463          10 :                                 assignTok->astOperand2()->varId() != var2->varId() &&
    2464           2 :                                 !isSameExpression(true,
    2465             :                                                   tok->astOperand2(),
    2466             :                                                   assignTok->astOperand2(),
    2467           2 :                                                   *mSettings,
    2468             :                                                   true,
    2469             :                                                   true))
    2470           0 :                                 continue;
    2471           6 :                             differentDomain = true;
    2472           6 :                             break;
    2473             :                         }
    2474          23 :                         if (!differentDomain && !isUniqueExpression(tok->astOperand2()))
    2475           8 :                             duplicateAssignExpressionError(var1, var2, false);
    2476          15 :                         else if (mSettings->certainty.isEnabled(Certainty::inconclusive))
    2477          15 :                             duplicateAssignExpressionError(var1, var2, true);
    2478             :                     }
    2479             :                 }
    2480             :             }
    2481        6161 :             auto isInsideLambdaCaptureList = [](const Token* tok) {
    2482        6161 :                 const Token* parent = tok->astParent();
    2483        7337 :                 while (Token::simpleMatch(parent, ","))
    2484        1176 :                     parent = parent->astParent();
    2485        6161 :                 return isLambdaCaptureList(parent);
    2486             :             };
    2487      234526 :             ErrorPath errorPath;
    2488      234526 :             if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>|+=|*=|<<=|>>=") && !isInsideLambdaCaptureList(tok)) {
    2489        6157 :                 if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true))
    2490         203 :                     continue;
    2491       22505 :                 const bool pointerDereference = (tok->astOperand1() && tok->astOperand1()->isUnaryOp("*")) ||
    2492       16551 :                                                 (tok->astOperand2() && tok->astOperand2()->isUnaryOp("*"));
    2493        5954 :                 const bool followVar = (!isConstVarExpression(tok) || Token::Match(tok, "%comp%|%oror%|&&")) && !pointerDereference;
    2494        5954 :                 if (isSameExpression(true,
    2495             :                                      tok->astOperand1(),
    2496             :                                      tok->astOperand2(),
    2497        5954 :                                      *mSettings,
    2498             :                                      true,
    2499             :                                      followVar,
    2500             :                                      &errorPath)) {
    2501         114 :                     if (isWithoutSideEffects(tok->astOperand1())) {
    2502         111 :                         const Token* loopTok = isInLoopCondition(tok);
    2503         113 :                         if (!loopTok ||
    2504           2 :                             !findExpressionChanged(tok, tok, loopTok->link()->next()->link(), *mSettings)) {
    2505         110 :                             const bool isEnum = tok->scope()->type == Scope::eEnum;
    2506         110 :                             const bool assignment = !isEnum && tok->str() == "=";
    2507         110 :                             if (assignment)
    2508          10 :                                 selfAssignmentError(tok, tok->astOperand1()->expressionString());
    2509         100 :                             else if (!isEnum) {
    2510          93 :                                 if (tok->isCpp() && mSettings->standards.cpp >= Standards::CPP11 && tok->str() == "==") {
    2511          23 :                                     const Token* parent = tok->astParent();
    2512          34 :                                     while (parent && parent->astParent()) {
    2513          11 :                                         parent = parent->astParent();
    2514             :                                     }
    2515          23 :                                     if (parent && parent->previous() && parent->previous()->str() == "static_assert") {
    2516           3 :                                         continue;
    2517             :                                     }
    2518             :                                 }
    2519          90 :                                 duplicateExpressionError(tok->astOperand1(), tok->astOperand2(), tok, std::move(errorPath));
    2520             :                             }
    2521             :                         }
    2522             :                     }
    2523        5845 :                 } else if (tok->str() == "=" && Token::simpleMatch(tok->astOperand2(), "=") &&
    2524           5 :                            isSameExpression(false,
    2525             :                                             tok->astOperand1(),
    2526             :                                             tok->astOperand2()->astOperand1(),
    2527           5 :                                             *mSettings,
    2528             :                                             true,
    2529             :                                             false)) {
    2530           2 :                     if (isWithoutSideEffects(tok->astOperand1())) {
    2531           2 :                         selfAssignmentError(tok, tok->astOperand1()->expressionString());
    2532             :                     }
    2533        5838 :                 } else if (isOppositeExpression(tok->astOperand1(),
    2534             :                                                 tok->astOperand2(),
    2535        5838 :                                                 *mSettings,
    2536             :                                                 false,
    2537             :                                                 true,
    2538          21 :                                                 &errorPath) &&
    2539        5855 :                            !Token::Match(tok, "=|-|-=|/|/=") &&
    2540          17 :                            isWithoutSideEffects(tok->astOperand1())) {
    2541          17 :                     oppositeExpressionError(tok, std::move(errorPath));
    2542        5821 :                 } else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative
    2543        9901 :                     if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() &&
    2544          66 :                         isSameExpression(true,
    2545             :                                          tok->astOperand2(),
    2546             :                                          tok->astOperand1()->astOperand2(),
    2547          66 :                                          *mSettings,
    2548             :                                          true,
    2549             :                                          followVar,
    2550        9901 :                                          &errorPath) &&
    2551           4 :                         isWithoutSideEffects(tok->astOperand2()))
    2552           3 :                         duplicateExpressionError(tok->astOperand2(), tok->astOperand1()->astOperand2(), tok, errorPath);
    2553        5507 :                     else if (tok->astOperand2() && isConstExpression(tok->astOperand1(), mSettings->library)) {
    2554         127 :                         auto checkDuplicate = [&](const Token* exp1, const Token* exp2, const Token* ast1) {
    2555         127 :                             if (isSameExpression(true, exp1, exp2, *mSettings, true, true, &errorPath) &&
    2556         133 :                                 isWithoutSideEffects(exp1) &&
    2557           6 :                                 isWithoutSideEffects(ast1->astOperand2()))
    2558           6 :                                 duplicateExpressionError(exp1, exp2, tok, errorPath, /*hasMultipleExpr*/ true);
    2559         127 :                         };
    2560        4287 :                         const Token *ast1 = tok->astOperand1();
    2561        4354 :                         while (ast1 && tok->str() == ast1->str()) { // chain of identical operators
    2562          67 :                             checkDuplicate(ast1->astOperand2(), tok->astOperand2(), ast1);
    2563          67 :                             if (ast1->astOperand1() && ast1->astOperand1()->str() != tok->str()) // check first condition in the chain
    2564          60 :                                 checkDuplicate(ast1->astOperand1(), tok->astOperand2(), ast1);
    2565          67 :                             ast1 = ast1->astOperand1();
    2566             :                         }
    2567             :                     }
    2568             :                 }
    2569      228369 :             } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
    2570         130 :                 if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) &&
    2571          12 :                     !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) &&
    2572         130 :                     isConstStatement(tok->astOperand1()) && isConstStatement(tok->astOperand2()))
    2573          10 :                     duplicateValueTernaryError(tok);
    2574          64 :                 else if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath))
    2575           2 :                     duplicateExpressionTernaryError(tok, std::move(errorPath));
    2576             :             }
    2577             :         }
    2578             :     }
    2579             : }
    2580             : 
    2581          21 : void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors)
    2582             : {
    2583          21 :     errors.emplace_back(opTok, "");
    2584             : 
    2585          21 :     const std::string& op = opTok ? opTok->str() : "&&";
    2586             : 
    2587          42 :     reportError(errors, Severity::style, "oppositeExpression", "Opposite expression on both sides of \'" + op + "\'.\n"
    2588             :                 "Finding the opposite expression on both sides of an operator is suspicious and might "
    2589             :                 "indicate a cut and paste or logic error. Please examine this code carefully to "
    2590          21 :                 "determine if it is correct.", CWE398, Certainty::normal);
    2591          21 : }
    2592             : 
    2593         103 : void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr)
    2594             : {
    2595         103 :     errors.emplace_back(opTok, "");
    2596             : 
    2597         206 :     const std::string& expr1 = tok1 ? tok1->expressionString() : "x";
    2598         206 :     const std::string& expr2 = tok2 ? tok2->expressionString() : "x";
    2599             : 
    2600         206 :     const std::string& op = opTok ? opTok->str() : "&&";
    2601         424 :     std::string msg = "Same expression " + (hasMultipleExpr ? "\'" + expr1 + "\'" + " found multiple times in chain of \'" + op + "\' operators" : "on both sides of \'" + op + "\'");
    2602         103 :     const char *id = "duplicateExpression";
    2603         103 :     if (expr1 != expr2 && (!opTok || Token::Match(opTok, "%oror%|%comp%|&&|?|!"))) {
    2604          54 :         id = "knownConditionTrueFalse";
    2605         162 :         std::string exprMsg = "The comparison \'" + expr1 + " " + op +  " " + expr2 + "\' is always ";
    2606          54 :         if (Token::Match(opTok, "==|>=|<="))
    2607          11 :             msg = exprMsg + "true";
    2608          43 :         else if (Token::Match(opTok, "!=|>|<"))
    2609          30 :             msg = exprMsg + "false";
    2610             :     }
    2611             : 
    2612         103 :     if (expr1 != expr2 && !Token::Match(tok1, "%num%|NULL|nullptr") && !Token::Match(tok2, "%num%|NULL|nullptr"))
    2613          25 :         msg += " because '" + expr1 + "' and '" + expr2 + "' represent the same value";
    2614             : 
    2615         103 :     reportError(errors, Severity::style, id, msg +
    2616         206 :                 (std::string(".\nFinding the same expression ") + (hasMultipleExpr ? "more than once in a condition" : "on both sides of an operator")) +
    2617             :                 " is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to "
    2618         103 :                 "determine if it is correct.", CWE398, Certainty::normal);
    2619         103 : }
    2620             : 
    2621          27 : void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive)
    2622             : {
    2623          54 :     const std::list<const Token *> toks = { tok2, tok1 };
    2624             : 
    2625          54 :     const std::string& var1 = tok1 ? tok1->str() : "x";
    2626          27 :     const std::string& var2 = tok2 ? tok2->str() : "x";
    2627             : 
    2628          54 :     reportError(toks, Severity::style, "duplicateAssignExpression",
    2629          54 :                 "Same expression used in consecutive assignments of '" + var1 + "' and '" + var2 + "'.\n"
    2630          54 :                 "Finding variables '" + var1 + "' and '" + var2 + "' that are assigned the same expression "
    2631             :                 "is suspicious and might indicate a cut and paste or logic error. Please examine this code carefully to "
    2632          54 :                 "determine if it is correct.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
    2633          27 : }
    2634             : 
    2635           6 : void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors)
    2636             : {
    2637           6 :     errors.emplace_back(tok, "");
    2638           6 :     reportError(errors, Severity::style, "duplicateExpressionTernary", "Same expression in both branches of ternary operator.\n"
    2639             :                 "Finding the same expression in both branches of ternary operator is suspicious as "
    2640          12 :                 "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
    2641           6 : }
    2642             : 
    2643          14 : void CheckOther::duplicateValueTernaryError(const Token *tok)
    2644             : {
    2645          14 :     reportError(tok, Severity::style, "duplicateValueTernary", "Same value in both branches of ternary operator.\n"
    2646             :                 "Finding the same value in both branches of ternary operator is suspicious as "
    2647          28 :                 "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
    2648          14 : }
    2649             : 
    2650          17 : void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
    2651             : {
    2652          17 :     reportError(tok, Severity::style,
    2653             :                 "selfAssignment",
    2654          34 :                 "$symbol:" + varname + "\n"
    2655          34 :                 "Redundant assignment of '$symbol' to itself.", CWE398, Certainty::normal);
    2656          17 : }
    2657             : 
    2658             : //-----------------------------------------------------------------------------
    2659             : // Check is a comparison of two variables leads to condition, which is
    2660             : // always true or false.
    2661             : // For instance: int a = 1; if(isless(a,a)){...}
    2662             : // In this case isless(a,a) always evaluates to false.
    2663             : //
    2664             : // Reference:
    2665             : // - http://www.cplusplus.com/reference/cmath/
    2666             : //-----------------------------------------------------------------------------
    2667        3807 : void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse()
    2668             : {
    2669        3807 :     if (!mSettings->severity.isEnabled(Severity::warning))
    2670        2322 :         return;
    2671             : 
    2672        1485 :     logChecker("CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse"); // warning
    2673             : 
    2674        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2675        8648 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    2676      234526 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    2677      227363 :             if (tok->isName() && Token::Match(tok, "isgreater|isless|islessgreater|isgreaterequal|islessequal ( %var% , %var% )")) {
    2678         145 :                 const int varidLeft = tok->tokAt(2)->varId();// get the left varid
    2679         145 :                 const int varidRight = tok->tokAt(4)->varId();// get the right varid
    2680             :                 // compare varids: if they are not zero but equal
    2681             :                 // --> the comparison function is called with the same variables
    2682         145 :                 if (varidLeft == varidRight) {
    2683           5 :                     const std::string& functionName = tok->str(); // store function name
    2684           5 :                     const std::string& varNameLeft = tok->strAt(2); // get the left variable name
    2685           5 :                     if (functionName == "isgreater" || functionName == "isless" || functionName == "islessgreater") {
    2686             :                         // e.g.: isgreater(x,x) --> (x)>(x) --> false
    2687           3 :                         checkComparisonFunctionIsAlwaysTrueOrFalseError(tok, functionName, varNameLeft, false);
    2688             :                     } else { // functionName == "isgreaterequal" || functionName == "islessequal"
    2689             :                         // e.g.: isgreaterequal(x,x) --> (x)>=(x) --> true
    2690           2 :                         checkComparisonFunctionIsAlwaysTrueOrFalseError(tok, functionName, varNameLeft, true);
    2691             :                     }
    2692             :                 }
    2693             :             }
    2694             :         }
    2695             :     }
    2696             : }
    2697           9 : void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result)
    2698             : {
    2699           9 :     const std::string strResult = bool_to_string(result);
    2700           9 :     const CWE cweResult = result ? CWE571 : CWE570;
    2701             : 
    2702           9 :     reportError(tok, Severity::warning, "comparisonFunctionIsAlwaysTrueOrFalse",
    2703          18 :                 "$symbol:" + functionName + "\n"
    2704          18 :                 "Comparison of two identical variables with $symbol(" + varName + "," + varName + ") always evaluates to " + strResult + ".\n"
    2705          18 :                 "The function $symbol is designed to compare two variables. Calling this function with one variable (" + varName + ") "
    2706          18 :                 "for both parameters leads to a statement which is always " + strResult + ".", cweResult, Certainty::normal);
    2707           9 : }
    2708             : 
    2709             : //---------------------------------------------------------------------------
    2710             : // Check testing sign of unsigned variables and pointers.
    2711             : //---------------------------------------------------------------------------
    2712        3807 : void CheckOther::checkSignOfUnsignedVariable()
    2713             : {
    2714        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsignedLessThanZero"))
    2715        2320 :         return;
    2716             : 
    2717        1487 :     logChecker("CheckOther::checkSignOfUnsignedVariable"); // style
    2718             : 
    2719        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2720             : 
    2721        8649 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    2722             :         // check all the code in the function
    2723      234526 :         for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    2724      227363 :             const ValueFlow::Value *zeroValue = nullptr;
    2725      227363 :             const Token *nonZeroExpr = nullptr;
    2726      227363 :             if (comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr)) {
    2727          30 :                 const ValueType* vt = nonZeroExpr->valueType();
    2728          30 :                 if (vt->pointer)
    2729          11 :                     pointerLessThanZeroError(tok, zeroValue);
    2730             :                 else
    2731          19 :                     unsignedLessThanZeroError(tok, zeroValue, nonZeroExpr->expressionString());
    2732      227333 :             } else if (testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) {
    2733          17 :                 const ValueType* vt = nonZeroExpr->valueType();
    2734          17 :                 if (vt->pointer)
    2735           6 :                     pointerPositiveError(tok, zeroValue);
    2736             :                 else
    2737          11 :                     unsignedPositiveError(tok, zeroValue, nonZeroExpr->expressionString());
    2738             :             }
    2739             :         }
    2740             :     }
    2741             : }
    2742             : 
    2743      227658 : bool CheckOther::comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress)
    2744             : {
    2745      227658 :     if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
    2746      226248 :         return false;
    2747             : 
    2748        1410 :     const ValueFlow::Value *v1 = tok->astOperand1()->getValue(0);
    2749        1410 :     const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0);
    2750             : 
    2751        1410 :     if (Token::Match(tok, "<|<=") && v2 && v2->isKnown()) {
    2752          68 :         zeroValue = v2;
    2753          68 :         nonZeroExpr = tok->astOperand1();
    2754        1342 :     } else if (Token::Match(tok, ">|>=") && v1 && v1->isKnown()) {
    2755          32 :         zeroValue = v1;
    2756          32 :         nonZeroExpr = tok->astOperand2();
    2757             :     } else {
    2758        1310 :         return false;
    2759             :     }
    2760             : 
    2761         100 :     if (const Variable* var = nonZeroExpr->variable())
    2762          60 :         if (var->typeStartToken()->isTemplateArg())
    2763           1 :             return suppress;
    2764             : 
    2765          99 :     const ValueType* vt = nonZeroExpr->valueType();
    2766          99 :     return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED);
    2767             : }
    2768             : 
    2769      227623 : bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr)
    2770             : {
    2771      227623 :     if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
    2772      226248 :         return false;
    2773             : 
    2774        1375 :     const ValueFlow::Value *v1 = tok->astOperand1()->getValue(0);
    2775        1375 :     const ValueFlow::Value *v2 = tok->astOperand2()->getValue(0);
    2776             : 
    2777        1375 :     if (Token::simpleMatch(tok, ">=") && v2 && v2->isKnown()) {
    2778          30 :         zeroValue = v2;
    2779          30 :         nonZeroExpr = tok->astOperand1();
    2780        1345 :     } else if (Token::simpleMatch(tok, "<=") && v1 && v1->isKnown()) {
    2781          11 :         zeroValue = v1;
    2782          11 :         nonZeroExpr = tok->astOperand2();
    2783             :     } else {
    2784        1334 :         return false;
    2785             :     }
    2786             : 
    2787          41 :     const ValueType* vt = nonZeroExpr->valueType();
    2788          41 :     return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED);
    2789             : }
    2790             : 
    2791          23 : void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
    2792             : {
    2793          23 :     reportError(getErrorPath(tok, v, "Unsigned less than zero"), Severity::style, "unsignedLessThanZero",
    2794          46 :                 "$symbol:" + varname + "\n"
    2795             :                 "Checking if unsigned expression '$symbol' is less than zero.\n"
    2796             :                 "The unsigned expression '$symbol' will never be negative so it "
    2797          23 :                 "is either pointless or an error to check if it is.", CWE570, Certainty::normal);
    2798          23 : }
    2799             : 
    2800          15 : void CheckOther::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v)
    2801             : {
    2802          15 :     reportError(getErrorPath(tok, v, "Pointer less than zero"), Severity::style, "pointerLessThanZero",
    2803          30 :                 "A pointer can not be negative so it is either pointless or an error to check if it is.", CWE570, Certainty::normal);
    2804          15 : }
    2805             : 
    2806          15 : void CheckOther::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
    2807             : {
    2808          15 :     reportError(getErrorPath(tok, v, "Unsigned positive"), Severity::style, "unsignedPositive",
    2809          30 :                 "$symbol:" + varname + "\n"
    2810          15 :                 "Unsigned expression '$symbol' can't be negative so it is unnecessary to test it.", CWE570, Certainty::normal);
    2811          15 : }
    2812             : 
    2813          10 : void CheckOther::pointerPositiveError(const Token *tok, const ValueFlow::Value * v)
    2814             : {
    2815          10 :     reportError(getErrorPath(tok, v, "Pointer positive"), Severity::style, "pointerPositive",
    2816          20 :                 "A pointer can not be negative so it is either pointless or an error to check if it is not.", CWE570, Certainty::normal);
    2817          10 : }
    2818             : 
    2819             : /* check if a constructor in given class scope takes a reference */
    2820           5 : static bool constructorTakesReference(const Scope * const classScope)
    2821             : {
    2822           5 :     return std::any_of(classScope->functionList.begin(), classScope->functionList.end(), [&](const Function& constructor) {
    2823           6 :         if (constructor.isConstructor()) {
    2824           6 :             for (int argnr = 0U; argnr < constructor.argCount(); argnr++) {
    2825           4 :                 const Variable * const argVar = constructor.getArgumentVar(argnr);
    2826           4 :                 if (argVar && argVar->isReference()) {
    2827           3 :                     return true;
    2828             :                 }
    2829             :             }
    2830             :         }
    2831           3 :         return false;
    2832           5 :     });
    2833             : }
    2834             : 
    2835             : //---------------------------------------------------------------------------
    2836             : // This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &".
    2837             : // In most scenarios, "const A & a = getA()" will be more efficient.
    2838             : //---------------------------------------------------------------------------
    2839        3807 : void CheckOther::checkRedundantCopy()
    2840             : {
    2841        3807 :     if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings->certainty.isEnabled(Certainty::inconclusive))
    2842        2523 :         return;
    2843             : 
    2844        1284 :     logChecker("CheckOther::checkRedundantCopy"); // c++,performance,inconclusive
    2845             : 
    2846        1284 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2847             : 
    2848       14353 :     for (const Variable* var : symbolDatabase->variableList()) {
    2849       19022 :         if (!var || var->isReference() || var->isPointer() ||
    2850       32575 :             (!var->type() && !var->isStlType()) || // bailout if var is of standard type, if it is a pointer or non-const
    2851         646 :             (!var->isConst() && isVariableChanged(var, *mSettings)))
    2852       12616 :             continue;
    2853             : 
    2854         453 :         const Token* startTok = var->nameToken();
    2855         453 :         if (startTok->strAt(1) == "=") // %type% %name% = ... ;
    2856             :             ;
    2857         443 :         else if (Token::Match(startTok->next(), "(|{") && var->isClass() && var->typeScope()) {
    2858             :             // Object is instantiated. Warn if constructor takes arguments by value.
    2859           5 :             if (constructorTakesReference(var->typeScope()))
    2860           3 :                 continue;
    2861         438 :         } else if (Token::simpleMatch(startTok->next(), ";") && startTok->next()->isSplittedVarDeclEq()) {
    2862          25 :             startTok = startTok->tokAt(2);
    2863             :         } else
    2864         413 :             continue;
    2865             : 
    2866          37 :         const Token* tok = startTok->next()->astOperand2();
    2867          37 :         if (!tok)
    2868           0 :             continue;
    2869          37 :         if (!Token::Match(tok->previous(), "%name% ("))
    2870          20 :             continue;
    2871          17 :         if (!Token::Match(tok->link(), ") )| ;")) // bailout for usage like "const A a = getA()+3"
    2872           0 :             continue;
    2873             : 
    2874          17 :         const Token* dot = tok->astOperand1();
    2875          17 :         if (Token::simpleMatch(dot, ".")) {
    2876           9 :             if (dot->astOperand1() && isVariableChanged(dot->astOperand1()->variable(), *mSettings))
    2877           3 :                 continue;
    2878           6 :             if (isTemporary(dot, &mSettings->library, /*unknown*/ true))
    2879           2 :                 continue;
    2880             :         }
    2881          12 :         if (exprDependsOnThis(tok->previous()))
    2882           1 :             continue;
    2883             : 
    2884          11 :         const Function* func = tok->previous()->function();
    2885          11 :         if (func && func->tokenDef->strAt(-1) == "&") {
    2886           7 :             const Scope* fScope = func->functionScope;
    2887           7 :             if (fScope && fScope->bodyEnd && Token::Match(fScope->bodyEnd->tokAt(-3), "return %var% ;")) {
    2888           6 :                 const Token* varTok = fScope->bodyEnd->tokAt(-2);
    2889          16 :                 if (varTok->variable() && !varTok->variable()->isGlobal() &&
    2890          13 :                     (!varTok->variable()->type() || !varTok->variable()->type()->classScope ||
    2891           6 :                      (varTok->variable()->valueType() && ValueFlow::getSizeOf(*varTok->variable()->valueType(), *mSettings) > 2 * mSettings->platform.sizeof_pointer)))
    2892           5 :                     redundantCopyError(startTok, startTok->str());
    2893             :             }
    2894             :         }
    2895             :     }
    2896             : }
    2897             : 
    2898           9 : void CheckOther::redundantCopyError(const Token *tok,const std::string& varname)
    2899             : {
    2900           9 :     reportError(tok, Severity::performance, "redundantCopyLocalConst",
    2901          18 :                 "$symbol:" + varname + "\n"
    2902             :                 "Use const reference for '$symbol' to avoid unnecessary data copying.\n"
    2903             :                 "The const variable '$symbol' is assigned a copy of the data. You can avoid "
    2904           9 :                 "the unnecessary data copying by converting '$symbol' to const reference.",
    2905             :                 CWE398,
    2906          18 :                 Certainty::inconclusive); // since #5618 that check became inconclusive
    2907           9 : }
    2908             : 
    2909             : //---------------------------------------------------------------------------
    2910             : // Checking for shift by negative values
    2911             : //---------------------------------------------------------------------------
    2912             : 
    2913          58 : static bool isNegative(const Token *tok, const Settings &settings)
    2914             : {
    2915          58 :     return tok->valueType() && tok->valueType()->sign == ValueType::SIGNED && tok->getValueLE(-1LL, settings);
    2916             : }
    2917             : 
    2918        3807 : void CheckOther::checkNegativeBitwiseShift()
    2919             : {
    2920        3807 :     const bool portability = mSettings->severity.isEnabled(Severity::portability);
    2921             : 
    2922        3807 :     logChecker("CheckOther::checkNegativeBitwiseShift");
    2923             : 
    2924      358001 :     for (const Token* tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    2925      354194 :         if (!tok->astOperand1() || !tok->astOperand2())
    2926      304095 :             continue;
    2927             : 
    2928       50099 :         if (!Token::Match(tok, "<<|>>|<<=|>>="))
    2929       49951 :             continue;
    2930             : 
    2931             :         // don't warn if lhs is a class. this is an overloaded operator then
    2932         148 :         if (tok->isCpp()) {
    2933         147 :             const ValueType * lhsType = tok->astOperand1()->valueType();
    2934         147 :             if (!lhsType || !lhsType->isIntegral())
    2935         116 :                 continue;
    2936             :         }
    2937             : 
    2938             :         // bailout if operation is protected by ?:
    2939          32 :         bool ternary = false;
    2940         124 :         for (const Token *parent = tok; parent; parent = parent->astParent()) {
    2941          93 :             if (Token::Match(parent, "?|:")) {
    2942           1 :                 ternary = true;
    2943           1 :                 break;
    2944             :             }
    2945             :         }
    2946          32 :         if (ternary)
    2947           1 :             continue;
    2948             : 
    2949             :         // Get negative rhs value. preferably a value which doesn't have 'condition'.
    2950          31 :         if (portability && isNegative(tok->astOperand1(), *mSettings))
    2951           4 :             negativeBitwiseShiftError(tok, 1);
    2952          27 :         else if (isNegative(tok->astOperand2(), *mSettings))
    2953           6 :             negativeBitwiseShiftError(tok, 2);
    2954             :     }
    2955        3807 : }
    2956             : 
    2957             : 
    2958          18 : void CheckOther::negativeBitwiseShiftError(const Token *tok, int op)
    2959             : {
    2960          18 :     if (op == 1)
    2961             :         // LHS - this is used by intention in various software, if it
    2962             :         // is used often in a project and works as expected then this is
    2963             :         // a portability issue
    2964           8 :         reportError(tok, Severity::portability, "shiftNegativeLHS", "Shifting a negative value is technically undefined behaviour", CWE758, Certainty::normal);
    2965             :     else // RHS
    2966          10 :         reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value is undefined behaviour", CWE758, Certainty::normal);
    2967          18 : }
    2968             : 
    2969             : //---------------------------------------------------------------------------
    2970             : // Check for incompletely filled buffers.
    2971             : //---------------------------------------------------------------------------
    2972        3807 : void CheckOther::checkIncompleteArrayFill()
    2973             : {
    2974        3807 :     if (!mSettings->certainty.isEnabled(Certainty::inconclusive))
    2975        2420 :         return;
    2976        1387 :     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
    2977        1387 :     const bool printPortability = mSettings->severity.isEnabled(Severity::portability);
    2978        1387 :     if (!printPortability && !printWarning)
    2979           0 :         return;
    2980             : 
    2981        1387 :     logChecker("CheckOther::checkIncompleteArrayFill"); // warning,portability,inconclusive
    2982             : 
    2983        1387 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    2984             : 
    2985        8442 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    2986      232368 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    2987      225313 :             if (Token::Match(tok, "memset|memcpy|memmove (") && Token::Match(tok->linkAt(1)->tokAt(-2), ", %num% )")) {
    2988          88 :                 const Token* tok2 = tok->tokAt(2);
    2989          88 :                 if (tok2->str() == "::")
    2990           1 :                     tok2 = tok2->next();
    2991          94 :                 while (Token::Match(tok2, "%name% ::|."))
    2992           6 :                     tok2 = tok2->tokAt(2);
    2993          88 :                 if (!Token::Match(tok2, "%var% ,"))
    2994          17 :                     continue;
    2995             : 
    2996          71 :                 const Variable *var = tok2->variable();
    2997          71 :                 if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0))
    2998          37 :                     continue;
    2999             : 
    3000          34 :                 if (MathLib::toBigNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) {
    3001           9 :                     int size = mTokenizer->sizeOfType(var->typeStartToken());
    3002           9 :                     if (size == 0 && var->valueType()->pointer)
    3003           1 :                         size = mSettings->platform.sizeof_pointer;
    3004           8 :                     else if (size == 0 && var->valueType())
    3005           2 :                         size = ValueFlow::getSizeOf(*var->valueType(), *mSettings);
    3006           9 :                     const Token* tok3 = tok->next()->astOperand2()->astOperand1()->astOperand1();
    3007           9 :                     if ((size != 1 && size != 100 && size != 0) || var->isPointer()) {
    3008           6 :                         if (printWarning)
    3009           6 :                             incompleteArrayFillError(tok, tok3->expressionString(), tok->str(), false);
    3010           3 :                     } else if (var->valueType()->type == ValueType::Type::BOOL && printPortability) // sizeof(bool) is not 1 on all platforms
    3011           1 :                         incompleteArrayFillError(tok, tok3->expressionString(), tok->str(), true);
    3012             :                 }
    3013             :             }
    3014             :         }
    3015             :     }
    3016             : }
    3017             : 
    3018          11 : void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean)
    3019             : {
    3020          11 :     if (boolean)
    3021           1 :         reportError(tok, Severity::portability, "incompleteArrayFill",
    3022           2 :                     "$symbol:" + buffer + "\n"
    3023           2 :                     "$symbol:" + function + "\n"
    3024           2 :                     "Array '" + buffer + "' might be filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
    3025           2 :                     "The array '" + buffer + "' is filled incompletely. The function '" + function + "()' needs the size given in bytes, but the type 'bool' is larger than 1 on some platforms. Did you forget to multiply the size with 'sizeof(*" + buffer + ")'?", CWE131, Certainty::inconclusive);
    3026             :     else
    3027          10 :         reportError(tok, Severity::warning, "incompleteArrayFill",
    3028          20 :                     "$symbol:" + buffer + "\n"
    3029          20 :                     "$symbol:" + function + "\n"
    3030          20 :                     "Array '" + buffer + "' is filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
    3031          20 :                     "The array '" + buffer + "' is filled incompletely. The function '" + function + "()' needs the size given in bytes, but an element of the given array is larger than one byte. Did you forget to multiply the size with 'sizeof(*" + buffer + ")'?", CWE131, Certainty::inconclusive);
    3032          11 : }
    3033             : 
    3034             : //---------------------------------------------------------------------------
    3035             : // Detect NULL being passed to variadic function.
    3036             : //---------------------------------------------------------------------------
    3037             : 
    3038        3807 : void CheckOther::checkVarFuncNullUB()
    3039             : {
    3040        3807 :     if (!mSettings->severity.isEnabled(Severity::portability))
    3041        2322 :         return;
    3042             : 
    3043        1485 :     logChecker("CheckOther::checkVarFuncNullUB"); // portability
    3044             : 
    3045        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3046        8648 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    3047      241689 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    3048             :             // Is NULL passed to a function?
    3049      234526 :             if (Token::Match(tok,"[(,] NULL [,)]")) {
    3050             :                 // Locate function name in this function call.
    3051        1284 :                 const Token *ftok = tok;
    3052        1284 :                 int argnr = 1;
    3053        3802 :                 while (ftok && ftok->str() != "(") {
    3054        2518 :                     if (ftok->str() == ")")
    3055           4 :                         ftok = ftok->link();
    3056        2514 :                     else if (ftok->str() == ",")
    3057        1233 :                         ++argnr;
    3058        2518 :                     ftok = ftok->previous();
    3059             :                 }
    3060        1284 :                 ftok = ftok ? ftok->previous() : nullptr;
    3061        1284 :                 if (ftok && ftok->isName()) {
    3062             :                     // If this is a variadic function then report error
    3063        1283 :                     const Function *f = ftok->function();
    3064        1283 :                     if (f && f->argCount() <= argnr) {
    3065           1 :                         const Token *tok2 = f->argDef;
    3066           1 :                         tok2 = tok2 ? tok2->link() : nullptr; // goto ')'
    3067           1 :                         if (tok2 && Token::simpleMatch(tok2->tokAt(-1), "..."))
    3068           1 :                             varFuncNullUBError(tok);
    3069             :                     }
    3070             :                 }
    3071             :             }
    3072             :         }
    3073             :     }
    3074             : }
    3075             : 
    3076           5 : void CheckOther::varFuncNullUBError(const Token *tok)
    3077             : {
    3078           5 :     reportError(tok,
    3079             :                 Severity::portability,
    3080             :                 "varFuncNullUB",
    3081             :                 "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
    3082             :                 "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
    3083             :                 "The C99 standard, in section 7.15.1.1, states that if the type used by va_arg() is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined.\n"
    3084             :                 "The value of the NULL macro is an implementation-defined null pointer constant (7.17), which can be any integer constant expression with the value 0, or such an expression casted to (void*) (6.3.2.3). This includes values like 0, 0L, or even 0LL.\n"
    3085             :                 "In practice on common architectures, this will cause real crashes if sizeof(int) != sizeof(void*), and NULL is defined to 0 or any other null pointer constant that promotes to int.\n"
    3086             :                 "To reproduce you might be able to use this little code example on 64bit platforms. If the output includes \"ERROR\", the sentinel had only 4 out of 8 bytes initialized to zero and was not detected as the final argument to stop argument processing via va_arg(). Changing the 0 to (void*)0 or 0L will make the \"ERROR\" output go away.\n"
    3087             :                 "#include <stdarg.h>\n"
    3088             :                 "#include <stdio.h>\n"
    3089             :                 "\n"
    3090             :                 "void f(char *s, ...) {\n"
    3091             :                 "    va_list ap;\n"
    3092             :                 "    va_start(ap,s);\n"
    3093             :                 "    for (;;) {\n"
    3094             :                 "        char *p = va_arg(ap,char*);\n"
    3095             :                 "        printf(\"%018p, %s\\n\", p, (long)p & 255 ? p : \"\");\n"
    3096             :                 "        if(!p) break;\n"
    3097             :                 "    }\n"
    3098             :                 "    va_end(ap);\n"
    3099             :                 "}\n"
    3100             :                 "\n"
    3101             :                 "void g() {\n"
    3102             :                 "    char *s2 = \"x\";\n"
    3103             :                 "    char *s3 = \"ERROR\";\n"
    3104             :                 "\n"
    3105             :                 "    // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64\n"
    3106             :                 "    f(\"first\", s2, s2, s2, s2, s2, 0, s3, (char*)0);\n"
    3107             :                 "}\n"
    3108             :                 "\n"
    3109             :                 "void h() {\n"
    3110             :                 "    int i;\n"
    3111             :                 "    volatile unsigned char a[1000];\n"
    3112             :                 "    for (i = 0; i<sizeof(a); i++)\n"
    3113             :                 "        a[i] = -1;\n"
    3114             :                 "}\n"
    3115             :                 "\n"
    3116             :                 "int main() {\n"
    3117             :                 "    h();\n"
    3118             :                 "    g();\n"
    3119             :                 "    return 0;\n"
    3120          10 :                 "}", CWE475, Certainty::normal);
    3121           5 : }
    3122             : 
    3123        3807 : void CheckOther::checkRedundantPointerOp()
    3124             : {
    3125        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantPointerOp"))
    3126        2321 :         return;
    3127             : 
    3128        1486 :     logChecker("CheckOther::checkRedundantPointerOp"); // style
    3129             : 
    3130      302847 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    3131      301361 :         if (tok->isExpandedMacro() && tok->str() == "(")
    3132         501 :             tok = tok->link();
    3133             : 
    3134      301361 :         bool addressOfDeref{};
    3135      603467 :         if (tok->isUnaryOp("&") && tok->astOperand1()->isUnaryOp("*"))
    3136           4 :             addressOfDeref = true;
    3137      602954 :         else if (tok->isUnaryOp("*") && tok->astOperand1()->isUnaryOp("&"))
    3138           5 :             addressOfDeref = false;
    3139             :         else
    3140      301352 :             continue;
    3141             : 
    3142             :         // variable
    3143           9 :         const Token *varTok = tok->astOperand1()->astOperand1();
    3144           9 :         if (!varTok || varTok->isExpandedMacro())
    3145           0 :             continue;
    3146             : 
    3147           9 :         if (!addressOfDeref) { // dereference of address
    3148           5 :             if (tok->isExpandedMacro())
    3149           1 :                 continue;
    3150           4 :             if (varTok->valueType() && varTok->valueType()->pointer && varTok->valueType()->reference == Reference::LValue)
    3151           0 :                 continue;
    3152             :         }
    3153             : 
    3154           8 :         const Variable *var = varTok->variable();
    3155           8 :         if (!var || (addressOfDeref && !var->isPointer()))
    3156           1 :             continue;
    3157             : 
    3158           7 :         redundantPointerOpError(tok, var->name(), false, addressOfDeref);
    3159             :     }
    3160             : }
    3161             : 
    3162          11 : void CheckOther::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref)
    3163             : {
    3164          22 :     std::string msg = "$symbol:" + varname + "\nRedundant pointer operation on '$symbol' - it's already a ";
    3165          11 :     msg += addressOfDeref ? "pointer." : "variable.";
    3166          11 :     reportError(tok, Severity::style, "redundantPointerOp", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
    3167          11 : }
    3168             : 
    3169        3807 : void CheckOther::checkInterlockedDecrement()
    3170             : {
    3171        3807 :     if (!mSettings->platform.isWindows()) {
    3172        3774 :         return;
    3173             :     }
    3174             : 
    3175          33 :     logChecker("CheckOther::checkInterlockedDecrement"); // windows-platform
    3176             : 
    3177       16889 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    3178       16856 :         if (tok->isName() && Token::Match(tok, "InterlockedDecrement ( & %name% ) ; if ( %name%|!|0")) {
    3179          20 :             const Token* interlockedVarTok = tok->tokAt(3);
    3180          20 :             const Token* checkStartTok =  interlockedVarTok->tokAt(5);
    3181          28 :             if ((Token::Match(checkStartTok, "0 %comp% %name% )") && checkStartTok->strAt(2) == interlockedVarTok->str()) ||
    3182          16 :                 (Token::Match(checkStartTok, "! %name% )") && checkStartTok->strAt(1) == interlockedVarTok->str()) ||
    3183          54 :                 (Token::Match(checkStartTok, "%name% )") && checkStartTok->str() == interlockedVarTok->str()) ||
    3184          14 :                 (Token::Match(checkStartTok, "%name% %comp% 0 )") && checkStartTok->str() == interlockedVarTok->str())) {
    3185          10 :                 raceAfterInterlockedDecrementError(checkStartTok);
    3186             :             }
    3187       16836 :         } else if (Token::Match(tok, "if ( ::| InterlockedDecrement ( & %name%")) {
    3188           6 :             const Token* condEnd = tok->next()->link();
    3189           6 :             const Token* funcTok = tok->tokAt(2);
    3190           6 :             const Token* firstAccessTok = funcTok->str() == "::" ? funcTok->tokAt(4) : funcTok->tokAt(3);
    3191           6 :             if (condEnd && condEnd->next() && condEnd->next()->link()) {
    3192           6 :                 const Token* ifEndTok = condEnd->next()->link();
    3193           6 :                 if (Token::Match(ifEndTok, "} return %name%")) {
    3194           2 :                     const Token* secondAccessTok = ifEndTok->tokAt(2);
    3195           2 :                     if (secondAccessTok->str() == firstAccessTok->str()) {
    3196           2 :                         raceAfterInterlockedDecrementError(secondAccessTok);
    3197             :                     }
    3198           4 :                 } else if (Token::Match(ifEndTok, "} else { return %name%")) {
    3199           4 :                     const Token* secondAccessTok = ifEndTok->tokAt(4);
    3200           4 :                     if (secondAccessTok->str() == firstAccessTok->str()) {
    3201           4 :                         raceAfterInterlockedDecrementError(secondAccessTok);
    3202             :                     }
    3203             :                 }
    3204             :             }
    3205             :         }
    3206             :     }
    3207             : }
    3208             : 
    3209          20 : void CheckOther::raceAfterInterlockedDecrementError(const Token* tok)
    3210             : {
    3211          20 :     reportError(tok, Severity::error, "raceAfterInterlockedDecrement",
    3212          40 :                 "Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.", CWE362, Certainty::normal);
    3213          20 : }
    3214             : 
    3215        3807 : void CheckOther::checkUnusedLabel()
    3216             : {
    3217        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("unusedLabel"))
    3218        2321 :         return;
    3219             : 
    3220        1486 :     logChecker("CheckOther::checkUnusedLabel"); // style,warning
    3221             : 
    3222        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3223        8649 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    3224        7163 :         const bool hasIfdef = mTokenizer->hasIfdef(scope->bodyStart, scope->bodyEnd);
    3225      241526 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    3226      234363 :             if (!tok->scope()->isExecutable())
    3227          27 :                 tok = tok->scope()->bodyEnd;
    3228             : 
    3229      234363 :             if (Token::Match(tok, "{|}|; %name% :") && !tok->tokAt(1)->isKeyword()) {
    3230          24 :                 const std::string tmp("goto " + tok->strAt(1));
    3231          12 :                 if (!Token::findsimplematch(scope->bodyStart->next(), tmp.c_str(), tmp.size(), scope->bodyEnd->previous()))
    3232           6 :                     unusedLabelError(tok->next(), tok->next()->scope()->type == Scope::eSwitch, hasIfdef);
    3233             :             }
    3234             :         }
    3235             :     }
    3236             : }
    3237             : 
    3238          22 : void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef)
    3239             : {
    3240          22 :     if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style))
    3241           0 :         return;
    3242             : 
    3243          44 :     std::string id = "unusedLabel";
    3244          22 :     if (inSwitch)
    3245          10 :         id += "Switch";
    3246          22 :     if (hasIfdef)
    3247           8 :         id += "Configuration";
    3248             : 
    3249          44 :     std::string msg = "$symbol:" + (tok ? tok->str() : emptyString) + "\nLabel '$symbol' is not used.";
    3250          22 :     if (hasIfdef)
    3251           8 :         msg += " There is #if in function body so the label might be used in code that is removed by the preprocessor.";
    3252          22 :     if (inSwitch)
    3253          10 :         msg += " Should this be a 'case' of the enclosing switch()?";
    3254             : 
    3255          22 :     reportError(tok,
    3256             :                 inSwitch ? Severity::warning : Severity::style,
    3257             :                 id,
    3258             :                 msg,
    3259             :                 CWE398,
    3260             :                 Certainty::normal);
    3261             : }
    3262             : 
    3263             : 
    3264        3807 : void CheckOther::checkEvaluationOrder()
    3265             : {
    3266             :     // This checker is not written according to C++11 sequencing rules
    3267        3807 :     if (mTokenizer->isCPP() && mSettings->standards.cpp >= Standards::CPP11)
    3268        3702 :         return;
    3269             : 
    3270         105 :     logChecker("CheckOther::checkEvaluationOrder"); // C/C++03
    3271             : 
    3272         105 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3273        2734 :     for (const Scope * functionScope : symbolDatabase->functionScopes) {
    3274      104419 :         for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
    3275      101790 :             if (tok->tokType() != Token::eIncDecOp && !tok->isAssignmentOp())
    3276      100753 :                 continue;
    3277        1037 :             if (!tok->astOperand1())
    3278           1 :                 continue;
    3279        1049 :             for (const Token *tok2 = tok;; tok2 = tok2->astParent()) {
    3280             :                 // If ast parent is a sequence point then break
    3281        1049 :                 const Token * const parent = tok2->astParent();
    3282        1049 :                 if (!parent)
    3283        1036 :                     break;
    3284          53 :                 if (Token::Match(parent, "%oror%|&&|?|:|;"))
    3285           3 :                     break;
    3286          50 :                 if (parent->str() == ",") {
    3287          12 :                     const Token *par = parent;
    3288          29 :                     while (Token::simpleMatch(par,","))
    3289          17 :                         par = par->astParent();
    3290             :                     // not function or in a while clause => break
    3291          12 :                     if (!(par && par->str() == "(" && par->astOperand2() && par->strAt(-1) != "while"))
    3292           5 :                         break;
    3293             :                     // control flow (if|while|etc) => break
    3294           7 :                     if (Token::simpleMatch(par->link(),") {"))
    3295           0 :                         break;
    3296             :                     // sequence point in function argument: dostuff((1,2),3) => break
    3297           7 :                     par = par->next();
    3298          16 :                     while (par && (par->previous() != parent))
    3299           9 :                         par = par->nextArgument();
    3300           7 :                     if (!par)
    3301           1 :                         break;
    3302             :                 }
    3303          44 :                 if (parent->str() == "(" && parent->astOperand2())
    3304          24 :                     break;
    3305             : 
    3306             :                 // self assignment..
    3307          17 :                 if (tok2 == tok &&
    3308          25 :                     tok->str() == "=" &&
    3309          45 :                     parent->str() == "=" &&
    3310           1 :                     isSameExpression(false, tok->astOperand1(), parent->astOperand1(), *mSettings, true, false)) {
    3311           2 :                     if (mSettings->severity.isEnabled(Severity::warning) &&
    3312           1 :                         isSameExpression(true, tok->astOperand1(), parent->astOperand1(), *mSettings, true, false))
    3313           1 :                         selfAssignmentError(parent, tok->astOperand1()->expressionString());
    3314           1 :                     break;
    3315             :                 }
    3316             : 
    3317             :                 // Is expression used?
    3318          19 :                 bool foundError = false;
    3319          19 :                 visitAstNodes((parent->astOperand1() != tok2) ? parent->astOperand1() : parent->astOperand2(),
    3320          24 :                               [&](const Token *tok3) {
    3321          24 :                     if (tok3->str() == "&" && !tok3->astOperand2())
    3322           1 :                         return ChildrenToVisit::none; // don't handle address-of for now
    3323          23 :                     if (tok3->str() == "(" && Token::simpleMatch(tok3->previous(), "sizeof"))
    3324           1 :                         return ChildrenToVisit::none; // don't care about sizeof usage
    3325          22 :                     if (isSameExpression(false, tok->astOperand1(), tok3, *mSettings, true, false))
    3326           6 :                         foundError = true;
    3327          22 :                     return foundError ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
    3328             :                 });
    3329             : 
    3330          19 :                 if (foundError) {
    3331           6 :                     unknownEvaluationOrder(parent);
    3332           6 :                     break;
    3333             :                 }
    3334          13 :             }
    3335             :         }
    3336             :     }
    3337             : }
    3338             : 
    3339          10 : void CheckOther::unknownEvaluationOrder(const Token* tok)
    3340             : {
    3341          10 :     reportError(tok, Severity::error, "unknownEvaluationOrder",
    3342          20 :                 "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal);
    3343          10 : }
    3344             : 
    3345        3807 : void CheckOther::checkAccessOfMovedVariable()
    3346             : {
    3347        3807 :     if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11 || !mSettings->severity.isEnabled(Severity::warning))
    3348        2424 :         return;
    3349        1381 :     logChecker("CheckOther::checkAccessOfMovedVariable"); // c++11,warning
    3350        1381 :     const bool reportInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
    3351        1381 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3352        5916 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    3353        4535 :         const Token * scopeStart = scope->bodyStart;
    3354        4535 :         if (scope->function) {
    3355        4526 :             const Token * memberInitializationStart = scope->function->constructorMemberInitialization();
    3356        4526 :             if (memberInitializationStart)
    3357          25 :                 scopeStart = memberInitializationStart;
    3358             :         }
    3359      132973 :         for (const Token* tok = scopeStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    3360      128438 :             if (!tok->astParent())
    3361      128412 :                 continue;
    3362       60899 :             const ValueFlow::Value * movedValue = tok->getMovedValue();
    3363       60899 :             if (!movedValue || movedValue->moveKind == ValueFlow::Value::MoveKind::NonMovedVariable)
    3364       60873 :                 continue;
    3365          26 :             if (movedValue->isInconclusive() && !reportInconclusive)
    3366           0 :                 continue;
    3367             : 
    3368          26 :             bool inconclusive = false;
    3369          26 :             bool accessOfMoved = false;
    3370          26 :             if (tok->strAt(1) == ".") {
    3371           3 :                 if (tok->next()->originalName() == "->")
    3372           2 :                     accessOfMoved = true;
    3373             :                 else
    3374           1 :                     inconclusive = true;
    3375             :             } else {
    3376          23 :                 const ExprUsage usage = getExprUsage(tok, 0, *mSettings);
    3377          23 :                 if (usage == ExprUsage::Used)
    3378          18 :                     accessOfMoved = true;
    3379          23 :                 if (usage == ExprUsage::PassedByReference)
    3380           3 :                     accessOfMoved = !isVariableChangedByFunctionCall(tok, 0, *mSettings, &inconclusive);
    3381          20 :                 else if (usage == ExprUsage::Inconclusive)
    3382           1 :                     inconclusive = true;
    3383             :             }
    3384          26 :             if (accessOfMoved || (inconclusive && reportInconclusive))
    3385          24 :                 accessMovedError(tok, tok->str(), movedValue, inconclusive || movedValue->isInconclusive());
    3386             :         }
    3387             :     }
    3388             : }
    3389             : 
    3390          28 : void CheckOther::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
    3391             : {
    3392          28 :     if (!tok) {
    3393           4 :         reportError(tok, Severity::warning, "accessMoved", "Access of moved variable 'v'.", CWE672, Certainty::normal);
    3394           4 :         reportError(tok, Severity::warning, "accessForwarded", "Access of forwarded variable 'v'.", CWE672, Certainty::normal);
    3395           4 :         return;
    3396             :     }
    3397             : 
    3398          24 :     const char * errorId = nullptr;
    3399          24 :     std::string kindString;
    3400          24 :     switch (value->moveKind) {
    3401          23 :     case ValueFlow::Value::MoveKind::MovedVariable:
    3402          23 :         errorId = "accessMoved";
    3403          23 :         kindString = "moved";
    3404          23 :         break;
    3405           1 :     case ValueFlow::Value::MoveKind::ForwardedVariable:
    3406           1 :         errorId = "accessForwarded";
    3407           1 :         kindString = "forwarded";
    3408           1 :         break;
    3409           0 :     default:
    3410           0 :         return;
    3411             :     }
    3412          72 :     const std::string errmsg("$symbol:" + varname + "\nAccess of " + kindString + " variable '$symbol'.");
    3413          48 :     const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
    3414          24 :     reportError(errorPath, Severity::warning, errorId, errmsg, CWE672, inconclusive ? Certainty::inconclusive : Certainty::normal);
    3415             : }
    3416             : 
    3417             : 
    3418             : 
    3419        3806 : void CheckOther::checkFuncArgNamesDifferent()
    3420             : {
    3421        3806 :     const bool style = mSettings->severity.isEnabled(Severity::style);
    3422        3806 :     const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
    3423        3807 :     const bool warning = mSettings->severity.isEnabled(Severity::warning);
    3424             : 
    3425        3807 :     if (!(warning || (style && inconclusive)) && !mSettings->isPremiumEnabled("funcArgNamesDifferent"))
    3426        2322 :         return;
    3427             : 
    3428        1485 :     logChecker("CheckOther::checkFuncArgNamesDifferent"); // style,warning,inconclusive
    3429             : 
    3430        1485 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3431             :     // check every function
    3432        8648 :     for (const Scope *scope : symbolDatabase->functionScopes) {
    3433        7163 :         const Function * function = scope->function;
    3434             :         // only check functions with arguments
    3435        7163 :         if (!function || function->argCount() == 0)
    3436        7137 :             continue;
    3437             : 
    3438             :         // only check functions with separate declarations and definitions
    3439        3112 :         if (function->argDef == function->arg)
    3440        3081 :             continue;
    3441             : 
    3442             :         // get the function argument name tokens
    3443          31 :         std::vector<const Token *>  declarations(function->argCount());
    3444          31 :         std::vector<const Token *>  definitions(function->argCount());
    3445          31 :         const Token * decl = function->argDef->next();
    3446          91 :         for (int j = 0; j < function->argCount(); ++j) {
    3447          60 :             declarations[j] = nullptr;
    3448          60 :             definitions[j] = nullptr;
    3449             :             // get the definition
    3450          60 :             const Variable * variable = function->getArgumentVar(j);
    3451          60 :             if (variable) {
    3452          60 :                 definitions[j] = variable->nameToken();
    3453             :             }
    3454             :             // get the declaration (search for first token with varId)
    3455         185 :             while (decl && !Token::Match(decl, ",|)|;")) {
    3456             :                 // skip everything after the assignment because
    3457             :                 // it could also have a varId or be the first
    3458             :                 // token with a varId if there is no name token
    3459         136 :                 if (decl->str() == "=") {
    3460          11 :                     decl = decl->nextArgument();
    3461          11 :                     break;
    3462             :                 }
    3463             :                 // skip over template
    3464         125 :                 if (decl->link())
    3465           0 :                     decl = decl->link();
    3466         125 :                 else if (decl->varId())
    3467          48 :                     declarations[j] = decl;
    3468         125 :                 decl = decl->next();
    3469             :             }
    3470          60 :             if (Token::simpleMatch(decl, ","))
    3471          22 :                 decl = decl->next();
    3472             :         }
    3473             :         // check for different argument order
    3474          31 :         if (warning) {
    3475          31 :             bool order_different = false;
    3476          91 :             for (int j = 0; j < function->argCount(); ++j) {
    3477          60 :                 if (!declarations[j] || !definitions[j] || declarations[j]->str() == definitions[j]->str())
    3478          43 :                     continue;
    3479             : 
    3480          50 :                 for (int k = 0; k < function->argCount(); ++k) {
    3481          41 :                     if (j != k && definitions[k] && declarations[j]->str() == definitions[k]->str()) {
    3482           8 :                         order_different = true;
    3483           8 :                         break;
    3484             :                     }
    3485             :                 }
    3486             :             }
    3487          31 :             if (order_different) {
    3488           5 :                 funcArgOrderDifferent(function->name(), function->argDef->next(), function->arg->next(), declarations, definitions);
    3489           5 :                 continue;
    3490             :             }
    3491             :         }
    3492             :         // check for different argument names
    3493          26 :         if (style && inconclusive) {
    3494          63 :             for (int j = 0; j < function->argCount(); ++j) {
    3495          39 :                 if (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str())
    3496           9 :                     funcArgNamesDifferent(function->name(), j, declarations[j], definitions[j]);
    3497             :             }
    3498             :         }
    3499             :     }
    3500             : }
    3501             : 
    3502          13 : void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg int index,
    3503             :                                        const Token* declaration, const Token* definition)
    3504             : {
    3505          26 :     std::list<const Token *> tokens = { declaration,definition };
    3506          13 :     reportError(tokens, Severity::style, "funcArgNamesDifferent",
    3507          26 :                 "$symbol:" + functionName + "\n"
    3508          52 :                 "Function '$symbol' argument " + std::to_string(index + 1) + " names different: declaration '" +
    3509          52 :                 (declaration ? declaration->str() : std::string("A")) + "' definition '" +
    3510          52 :                 (definition ? definition->str() : std::string("B")) + "'.", CWE628, Certainty::inconclusive);
    3511          13 : }
    3512             : 
    3513           9 : void CheckOther::funcArgOrderDifferent(const std::string & functionName,
    3514             :                                        const Token* declaration, const Token* definition,
    3515             :                                        const std::vector<const Token *> & declarations,
    3516             :                                        const std::vector<const Token *> & definitions)
    3517             : {
    3518             :     std::list<const Token *> tokens = {
    3519           9 :         !declarations.empty() ? declarations[0] ? declarations[0] : declaration : nullptr,
    3520           9 :         !definitions.empty() ? definitions[0] ? definitions[0] : definition : nullptr
    3521          27 :     };
    3522          18 :     std::string msg = "$symbol:" + functionName + "\nFunction '$symbol' argument order different: declaration '";
    3523          24 :     for (int i = 0; i < declarations.size(); ++i) {
    3524          15 :         if (i != 0)
    3525          10 :             msg += ", ";
    3526          15 :         if (declarations[i])
    3527          13 :             msg += declarations[i]->str();
    3528             :     }
    3529           9 :     msg += "' definition '";
    3530          24 :     for (int i = 0; i < definitions.size(); ++i) {
    3531          15 :         if (i != 0)
    3532          10 :             msg += ", ";
    3533          15 :         if (definitions[i])
    3534          15 :             msg += definitions[i]->str();
    3535             :     }
    3536           9 :     msg += "'";
    3537           9 :     reportError(tokens, Severity::warning, "funcArgOrderDifferent", msg, CWE683, Certainty::normal);
    3538           9 : }
    3539             : 
    3540       51772 : static const Token *findShadowed(const Scope *scope, const Variable& var, int linenr)
    3541             : {
    3542       51772 :     if (!scope)
    3543       38651 :         return nullptr;
    3544       13355 :     for (const Variable &v : scope->varlist) {
    3545         240 :         if (scope->isExecutable() && v.nameToken()->linenr() > linenr)
    3546          52 :             continue;
    3547         188 :         if (v.name() == var.name())
    3548           6 :             return v.nameToken();
    3549             :     }
    3550     4069212 :     auto it = std::find_if(scope->functionList.cbegin(), scope->functionList.cend(), [&](const Function& f) {
    3551     4069212 :         return f.type == Function::Type::eFunction && f.name() == var.name() && precedes(f.tokenDef, var.nameToken());
    3552       13115 :     });
    3553       13115 :     if (it != scope->functionList.end())
    3554           5 :         return it->tokenDef;
    3555             : 
    3556       13110 :     if (scope->type == Scope::eLambda)
    3557           0 :         return nullptr;
    3558       13110 :     const Token* shadowed = findShadowed(scope->nestedIn, var, linenr);
    3559       13110 :     if (!shadowed)
    3560       13109 :         shadowed = findShadowed(scope->functionOf, var, linenr);
    3561       13110 :     return shadowed;
    3562             : }
    3563             : 
    3564        3807 : void CheckOther::checkShadowVariables()
    3565             : {
    3566        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("shadowVariable"))
    3567        2321 :         return;
    3568        1486 :     logChecker("CheckOther::checkShadowVariables"); // style
    3569        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3570       12051 :     for (const Scope & scope : symbolDatabase->scopeList) {
    3571       10565 :         if (!scope.isExecutable() || scope.type == Scope::eLambda)
    3572        1989 :             continue;
    3573        8576 :         const Scope *functionScope = &scope;
    3574       10151 :         while (functionScope && functionScope->type != Scope::ScopeType::eFunction && functionScope->type != Scope::ScopeType::eLambda)
    3575        1575 :             functionScope = functionScope->nestedIn;
    3576       21361 :         for (const Variable &var : scope.varlist) {
    3577       12785 :             if (var.nameToken() && var.nameToken()->isExpandedMacro()) // #8903
    3578           2 :                 continue;
    3579             : 
    3580       12783 :             if (functionScope && functionScope->type == Scope::ScopeType::eFunction && functionScope->function) {
    3581       12782 :                 const auto argList = functionScope->function->argumentList;
    3582       11175 :                 auto it = std::find_if(argList.cbegin(), argList.cend(), [&](const Variable& arg) {
    3583       11175 :                     return arg.nameToken() && var.name() == arg.name();
    3584       12782 :                 });
    3585       12782 :                 if (it != argList.end()) {
    3586           1 :                     shadowError(var.nameToken(), it->nameToken(), "argument");
    3587           1 :                     continue;
    3588             :                 }
    3589             :             }
    3590             : 
    3591       12782 :             const Token *shadowed = findShadowed(scope.nestedIn, var, var.nameToken()->linenr());
    3592       12782 :             if (!shadowed)
    3593       12771 :                 shadowed = findShadowed(scope.functionOf, var, var.nameToken()->linenr());
    3594       12782 :             if (!shadowed)
    3595       12771 :                 continue;
    3596          11 :             if (scope.type == Scope::eFunction && scope.className == var.name())
    3597           3 :                 continue;
    3598           5 :             if (functionScope->functionOf && functionScope->functionOf->isClassOrStructOrUnion() && functionScope->function && functionScope->function->isStatic() &&
    3599          13 :                 shadowed->variable() && !shadowed->variable()->isLocal())
    3600           1 :                 continue;
    3601           7 :             shadowError(var.nameToken(), shadowed, (shadowed->varId() != 0) ? "variable" : "function");
    3602             :         }
    3603             :     }
    3604             : }
    3605             : 
    3606          20 : void CheckOther::shadowError(const Token *var, const Token *shadowed, const std::string& type)
    3607             : {
    3608          40 :     ErrorPath errorPath;
    3609          20 :     errorPath.emplace_back(shadowed, "Shadowed declaration");
    3610          20 :     errorPath.emplace_back(var, "Shadow variable");
    3611          20 :     const std::string &varname = var ? var->str() : type;
    3612          40 :     const std::string Type = char(std::toupper(type[0])) + type.substr(1);
    3613          40 :     const std::string id = "shadow" + Type;
    3614          60 :     const std::string message = "$symbol:" + varname + "\nLocal variable \'$symbol\' shadows outer " + type;
    3615          20 :     reportError(errorPath, Severity::style, id.c_str(), message, CWE398, Certainty::normal);
    3616          20 : }
    3617             : 
    3618         272 : static bool isVariableExpression(const Token* tok)
    3619             : {
    3620         272 :     if (tok->varId() != 0)
    3621         249 :         return true;
    3622          23 :     if (Token::simpleMatch(tok, "."))
    3623           2 :         return isVariableExpression(tok->astOperand1()) &&
    3624           2 :                isVariableExpression(tok->astOperand2());
    3625          22 :     if (Token::simpleMatch(tok, "["))
    3626           2 :         return isVariableExpression(tok->astOperand1());
    3627          20 :     return false;
    3628             : }
    3629             : 
    3630           9 : static bool isVariableExprHidden(const Token* tok)
    3631             : {
    3632           9 :     if (!tok)
    3633           0 :         return false;
    3634           9 :     if (!tok->astParent())
    3635           0 :         return false;
    3636           9 :     if (Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astSibling(), "0"))
    3637           2 :         return true;
    3638           7 :     if (Token::simpleMatch(tok->astParent(), "&&") && Token::simpleMatch(tok->astSibling(), "false"))
    3639           1 :         return true;
    3640           6 :     if (Token::simpleMatch(tok->astParent(), "||") && Token::simpleMatch(tok->astSibling(), "true"))
    3641           1 :         return true;
    3642           5 :     return false;
    3643             : }
    3644             : 
    3645        3807 : void CheckOther::checkKnownArgument()
    3646             : {
    3647        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownArgument"))
    3648        2321 :         return;
    3649        1486 :     logChecker("CheckOther::checkKnownArgument"); // style
    3650        1486 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3651        8649 :     for (const Scope *functionScope : symbolDatabase->functionScopes) {
    3652      241689 :         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
    3653      234526 :             if (!tok->hasKnownIntValue())
    3654      234517 :                 continue;
    3655       13262 :             if (Token::Match(tok, "++|--|%assign%"))
    3656        1237 :                 continue;
    3657       12025 :             if (!Token::Match(tok->astParent(), "(|{|,"))
    3658        5103 :                 continue;
    3659        6922 :             if (tok->astParent()->isCast() || (tok->isCast() && Token::Match(tok->astOperand2(), "++|--|%assign%")))
    3660         439 :                 continue;
    3661        6483 :             int argn = -1;
    3662        6483 :             const Token* ftok = getTokenArgumentFunction(tok, argn);
    3663        6483 :             if (!ftok)
    3664          58 :                 continue;
    3665        6425 :             if (ftok->isCast())
    3666           0 :                 continue;
    3667        6425 :             if (Token::Match(ftok, "if|while|switch|sizeof"))
    3668         243 :                 continue;
    3669        6182 :             if (tok == tok->astParent()->previous())
    3670        1244 :                 continue;
    3671        4938 :             if (isConstVarExpression(tok))
    3672        4667 :                 continue;
    3673         271 :             if (Token::Match(tok->astOperand1(), "%name% ("))
    3674           3 :                 continue;
    3675         268 :             const Token * tok2 = tok;
    3676         268 :             if (isCPPCast(tok2))
    3677           2 :                 tok2 = tok2->astOperand2();
    3678         268 :             if (isVariableExpression(tok2))
    3679         248 :                 continue;
    3680          22 :             if (tok->isComparisonOp() &&
    3681           2 :                 isSameExpression(
    3682           2 :                     true, tok->astOperand1(), tok->astOperand2(), *mSettings, true, true))
    3683           2 :                 continue;
    3684             :             // ensure that there is a integer variable in expression with unknown value
    3685          18 :             const Token* vartok = nullptr;
    3686          18 :             visitAstNodes(tok, [&](const Token* child) {
    3687          56 :                 if (Token::Match(child, "%var%|.|[")) {
    3688          20 :                     if (child->hasKnownIntValue())
    3689           4 :                         return ChildrenToVisit::none;
    3690          16 :                     if (astIsIntegral(child, false) && !astIsPointer(child) && child->values().empty()) {
    3691          10 :                         vartok = child;
    3692          10 :                         return ChildrenToVisit::done;
    3693             :                     }
    3694             :                 }
    3695          42 :                 return ChildrenToVisit::op1_and_op2;
    3696             :             });
    3697          18 :             if (!vartok)
    3698           8 :                 continue;
    3699          20 :             if (vartok->astSibling() &&
    3700          20 :                 findAstNode(vartok->astSibling(), [](const Token* child) {
    3701          14 :                 return Token::simpleMatch(child, "sizeof");
    3702             :             }))
    3703           0 :                 continue;
    3704             :             // ensure that function name does not contain "assert"
    3705          10 :             std::string funcname = ftok->str();
    3706          10 :             strTolower(funcname);
    3707          10 :             if (funcname.find("assert") != std::string::npos)
    3708           1 :                 continue;
    3709           9 :             knownArgumentError(tok, ftok, &tok->values().front(), vartok->expressionString(), isVariableExprHidden(vartok));
    3710             :         }
    3711             :     }
    3712             : }
    3713             : 
    3714          13 : void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden)
    3715             : {
    3716          13 :     if (!tok) {
    3717           4 :         reportError(tok, Severity::style, "knownArgument", "Argument 'x-x' to function 'func' is always 0. It does not matter what value 'x' has.");
    3718           4 :         reportError(tok, Severity::style, "knownArgumentHiddenVariableExpression", "Argument 'x*0' to function 'func' is always 0. Constant literal calculation disable/hide variable expression 'x'.");
    3719           4 :         return;
    3720             :     }
    3721             : 
    3722           9 :     const MathLib::bigint intvalue = value->intvalue;
    3723          18 :     const std::string &expr = tok->expressionString();
    3724           9 :     const std::string &fun = ftok->str();
    3725             : 
    3726          18 :     std::string ftype = "function ";
    3727           9 :     if (ftok->type())
    3728           1 :         ftype = "constructor ";
    3729           8 :     else if (fun == "{")
    3730           1 :         ftype = "init list ";
    3731             : 
    3732             :     const char *id;
    3733          27 :     std::string errmsg = "Argument '" + expr + "' to " + ftype + fun + " is always " + std::to_string(intvalue) + ". ";
    3734           9 :     if (!isVariableExpressionHidden) {
    3735           5 :         id = "knownArgument";
    3736           5 :         errmsg += "It does not matter what value '" + varexpr + "' has.";
    3737             :     } else {
    3738           4 :         id = "knownArgumentHiddenVariableExpression";
    3739           4 :         errmsg += "Constant literal calculation disable/hide variable expression '" + varexpr + "'.";
    3740             :     }
    3741             : 
    3742          18 :     const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
    3743           9 :     reportError(errorPath, Severity::style, id, errmsg, CWE570, Certainty::normal);
    3744             : }
    3745             : 
    3746        3807 : void CheckOther::checkKnownPointerToBool()
    3747             : {
    3748        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownPointerToBool"))
    3749        2321 :         return;
    3750        1486 :     logChecker("CheckOther::checkKnownPointerToBool"); // style
    3751        1486 :     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
    3752        8649 :     for (const Scope* functionScope : symbolDatabase->functionScopes) {
    3753      241689 :         for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
    3754      234526 :             if (!tok->hasKnownIntValue())
    3755      221264 :                 continue;
    3756       13262 :             if (!astIsPointer(tok))
    3757       12600 :                 continue;
    3758         662 :             if (Token::Match(tok->astParent(), "?|!|&&|%oror%|%comp%"))
    3759           1 :                 continue;
    3760         661 :             if (tok->astParent() && Token::Match(tok->astParent()->previous(), "if|while|switch|sizeof ("))
    3761           0 :                 continue;
    3762         661 :             if (tok->isExpandedMacro())
    3763           1 :                 continue;
    3764         660 :             if (findParent(tok, [](const Token* parent) {
    3765         649 :                 return parent->isExpandedMacro();
    3766             :             }))
    3767          13 :                 continue;
    3768         647 :             if (!isUsedAsBool(tok, *mSettings))
    3769         640 :                 continue;
    3770           7 :             const ValueFlow::Value& value = tok->values().front();
    3771           7 :             knownPointerToBoolError(tok, &value);
    3772             :         }
    3773             :     }
    3774             : }
    3775             : 
    3776          11 : void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value)
    3777             : {
    3778          11 :     if (!tok) {
    3779           4 :         reportError(tok, Severity::style, "knownPointerToBool", "Pointer expression 'p' converted to bool is always true.");
    3780           4 :         return;
    3781             :     }
    3782          14 :     std::string cond = bool_to_string(value->intvalue);
    3783          14 :     const std::string& expr = tok->expressionString();
    3784          21 :     std::string errmsg = "Pointer expression '" + expr + "' converted to bool is always " + cond + ".";
    3785          14 :     const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
    3786           7 :     reportError(errorPath, Severity::style, "knownPointerToBool", errmsg, CWE570, Certainty::normal);
    3787             : }
    3788             : 
    3789        3807 : void CheckOther::checkComparePointers()
    3790             : {
    3791        3807 :     logChecker("CheckOther::checkComparePointers");
    3792        3807 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3793       13281 :     for (const Scope *functionScope : symbolDatabase->functionScopes) {
    3794      281926 :         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
    3795      272452 :             if (!Token::Match(tok, "<|>|<=|>=|-"))
    3796      272444 :                 continue;
    3797        1174 :             const Token *tok1 = tok->astOperand1();
    3798        1174 :             const Token *tok2 = tok->astOperand2();
    3799        1174 :             if (!astIsPointer(tok1) || !astIsPointer(tok2))
    3800        1147 :                 continue;
    3801          27 :             ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1);
    3802          27 :             ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2);
    3803          27 :             if (!v1.isLocalLifetimeValue() || !v2.isLocalLifetimeValue())
    3804          15 :                 continue;
    3805          12 :             const Variable *var1 = v1.tokvalue->variable();
    3806          12 :             const Variable *var2 = v2.tokvalue->variable();
    3807          12 :             if (!var1 || !var2)
    3808           0 :                 continue;
    3809          12 :             if (v1.tokvalue->varId() == v2.tokvalue->varId())
    3810           3 :                 continue;
    3811           9 :             if (var1->isReference() || var2->isReference())
    3812           1 :                 continue;
    3813           8 :             if (var1->isRValueReference() || var2->isRValueReference())
    3814           0 :                 continue;
    3815           8 :             if (const Token* parent2 = getParentLifetime(v2.tokvalue, mSettings->library))
    3816           8 :                 if (var1 == parent2->variable())
    3817           0 :                     continue;
    3818           8 :             if (const Token* parent1 = getParentLifetime(v1.tokvalue, mSettings->library))
    3819           8 :                 if (var2 == parent1->variable())
    3820           0 :                     continue;
    3821           8 :             comparePointersError(tok, &v1, &v2);
    3822             :         }
    3823             :     }
    3824        3807 : }
    3825             : 
    3826          12 : void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2)
    3827             : {
    3828          24 :     ErrorPath errorPath;
    3829          12 :     std::string verb = "Comparing";
    3830          12 :     if (Token::simpleMatch(tok, "-"))
    3831           2 :         verb = "Subtracting";
    3832          12 :     const char * const id = (verb[0] == 'C') ? "comparePointers" : "subtractPointers";
    3833          12 :     if (v1) {
    3834           8 :         errorPath.emplace_back(v1->tokvalue->variable()->nameToken(), "Variable declared here.");
    3835           8 :         errorPath.insert(errorPath.end(), v1->errorPath.cbegin(), v1->errorPath.cend());
    3836             :     }
    3837          12 :     if (v2) {
    3838           8 :         errorPath.emplace_back(v2->tokvalue->variable()->nameToken(), "Variable declared here.");
    3839           8 :         errorPath.insert(errorPath.end(), v2->errorPath.cbegin(), v2->errorPath.cend());
    3840             :     }
    3841          12 :     errorPath.emplace_back(tok, "");
    3842          12 :     reportError(
    3843          24 :         errorPath, Severity::error, id, verb + " pointers that point to different objects", CWE570, Certainty::normal);
    3844          12 : }
    3845             : 
    3846        3807 : void CheckOther::checkModuloOfOne()
    3847             : {
    3848        3807 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("moduloofone"))
    3849        2321 :         return;
    3850             : 
    3851        1486 :     logChecker("CheckOther::checkModuloOfOne"); // style
    3852             : 
    3853      306127 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    3854      304641 :         if (!tok->astOperand2() || !tok->astOperand1())
    3855      256513 :             continue;
    3856       48128 :         if (tok->str() != "%")
    3857       48092 :             continue;
    3858          36 :         if (!tok->valueType() || !tok->valueType()->isIntegral())
    3859           7 :             continue;
    3860             : 
    3861             :         // Value flow..
    3862          29 :         const ValueFlow::Value *value = tok->astOperand2()->getValue(1LL);
    3863          29 :         if (value && value->isKnown())
    3864          17 :             checkModuloOfOneError(tok);
    3865             :     }
    3866             : }
    3867             : 
    3868          21 : void CheckOther::checkModuloOfOneError(const Token *tok)
    3869             : {
    3870          21 :     reportError(tok, Severity::style, "moduloofone", "Modulo of one is always equal to zero");
    3871          21 : }
    3872             : 
    3873             : //-----------------------------------------------------------------------------
    3874             : // Overlapping write (undefined behavior)
    3875             : //-----------------------------------------------------------------------------
    3876         330 : static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigint *offset, const Settings& settings, MathLib::bigint* sizeValue = nullptr)
    3877             : {
    3878         330 :     if (!expr)
    3879           0 :         return false;
    3880             :     const Token *bufToken, *offsetToken;
    3881         330 :     MathLib::bigint elementSize = 0;
    3882         660 :     if (expr->isUnaryOp("&") && Token::simpleMatch(expr->astOperand1(), "[")) {
    3883          48 :         bufToken = expr->astOperand1()->astOperand1();
    3884          48 :         offsetToken = expr->astOperand1()->astOperand2();
    3885          48 :         if (expr->astOperand1()->valueType())
    3886          48 :             elementSize =  ValueFlow::getSizeOf(*expr->astOperand1()->valueType(), settings);
    3887         282 :     } else if (Token::Match(expr, "+|-") && expr->isBinaryOp()) {
    3888          48 :         const bool pointer1 = (expr->astOperand1()->valueType() && expr->astOperand1()->valueType()->pointer > 0);
    3889          48 :         const bool pointer2 = (expr->astOperand2()->valueType() && expr->astOperand2()->valueType()->pointer > 0);
    3890          48 :         if (pointer1 && !pointer2) {
    3891          48 :             bufToken = expr->astOperand1();
    3892          48 :             offsetToken = expr->astOperand2();
    3893          48 :             auto vt = *expr->astOperand1()->valueType();
    3894          48 :             --vt.pointer;
    3895          48 :             elementSize = ValueFlow::getSizeOf(vt, settings);
    3896           0 :         } else if (!pointer1 && pointer2) {
    3897           0 :             bufToken = expr->astOperand2();
    3898           0 :             offsetToken = expr->astOperand1();
    3899           0 :             auto vt = *expr->astOperand2()->valueType();
    3900           0 :             --vt.pointer;
    3901           0 :             elementSize = ValueFlow::getSizeOf(vt, settings);
    3902             :         } else {
    3903           0 :             return false;
    3904             :         }
    3905         234 :     } else if (expr->valueType() && expr->valueType()->pointer > 0) {
    3906         233 :         buf = expr;
    3907         233 :         *offset = 0;
    3908         233 :         auto vt = *expr->valueType();
    3909         233 :         --vt.pointer;
    3910         233 :         elementSize = ValueFlow::getSizeOf(vt, settings);
    3911         233 :         if (elementSize > 0) {
    3912         233 :             *offset *= elementSize;
    3913         233 :             if (sizeValue)
    3914          32 :                 *sizeValue *= elementSize;
    3915             :         }
    3916         233 :         return true;
    3917             :     } else {
    3918           1 :         return false;
    3919             :     }
    3920          96 :     if (!bufToken->valueType() || !bufToken->valueType()->pointer)
    3921           0 :         return false;
    3922          96 :     if (!offsetToken->hasKnownIntValue())
    3923           0 :         return false;
    3924          96 :     buf = bufToken;
    3925          96 :     *offset = offsetToken->getKnownIntValue();
    3926          96 :     if (elementSize > 0) {
    3927          96 :         *offset *= elementSize;
    3928          96 :         if (sizeValue)
    3929          10 :             *sizeValue *= elementSize;
    3930             :     }
    3931          96 :     return true;
    3932             : }
    3933             : 
    3934        3807 : void CheckOther::checkOverlappingWrite()
    3935             : {
    3936        3807 :     logChecker("CheckOther::checkOverlappingWrite");
    3937        3807 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    3938       13281 :     for (const Scope *functionScope : symbolDatabase->functionScopes) {
    3939      281926 :         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
    3940      272452 :             if (tok->isAssignmentOp()) {
    3941             :                 // check if LHS is a union member..
    3942        5103 :                 const Token * const lhs = tok->astOperand1();
    3943        5103 :                 if (!Token::simpleMatch(lhs, ".") || !lhs->isBinaryOp())
    3944        5099 :                     continue;
    3945          57 :                 const Variable * const lhsvar = lhs->astOperand1()->variable();
    3946          57 :                 if (!lhsvar || !lhsvar->typeScope() || lhsvar->typeScope()->type != Scope::ScopeType::eUnion)
    3947          53 :                     continue;
    3948           4 :                 const Token* const lhsmember = lhs->astOperand2();
    3949           4 :                 if (!lhsmember)
    3950           0 :                     continue;
    3951             : 
    3952             :                 // Is other union member used in RHS?
    3953           4 :                 const Token *errorToken = nullptr;
    3954           4 :                 visitAstNodes(tok->astOperand2(), [lhsvar, lhsmember, &errorToken](const Token *rhs) {
    3955           6 :                     if (!Token::simpleMatch(rhs, "."))
    3956           4 :                         return ChildrenToVisit::op1_and_op2;
    3957           2 :                     if (!rhs->isBinaryOp() || rhs->astOperand1()->variable() != lhsvar)
    3958           0 :                         return ChildrenToVisit::none;
    3959           2 :                     if (lhsmember->str() == rhs->astOperand2()->str())
    3960           0 :                         return ChildrenToVisit::none;
    3961           2 :                     const Variable* rhsmembervar = rhs->astOperand2()->variable();
    3962           2 :                     const Scope* varscope1 = lhsmember->variable() ? lhsmember->variable()->typeStartToken()->scope() : nullptr;
    3963           2 :                     const Scope* varscope2 = rhsmembervar ? rhsmembervar->typeStartToken()->scope() : nullptr;
    3964           2 :                     if (varscope1 && varscope1 == varscope2 && varscope1 != lhsvar->typeScope())
    3965             :                         // lhsmember and rhsmember are declared in same anonymous scope inside union
    3966           1 :                         return ChildrenToVisit::none;
    3967           1 :                     errorToken = rhs->astOperand2();
    3968           1 :                     return ChildrenToVisit::done;
    3969             :                 });
    3970           4 :                 if (errorToken)
    3971           1 :                     overlappingWriteUnion(tok);
    3972      267349 :             } else if (Token::Match(tok, "%name% (")) {
    3973       17744 :                 const Library::NonOverlappingData *nonOverlappingData = mSettings->library.getNonOverlappingData(tok);
    3974       17744 :                 if (!nonOverlappingData)
    3975       17685 :                     continue;
    3976         910 :                 const std::vector<const Token *> args = getArguments(tok);
    3977         910 :                 if (nonOverlappingData->ptr1Arg <= 0 || nonOverlappingData->ptr1Arg > args.size())
    3978           0 :                     continue;
    3979         910 :                 if (nonOverlappingData->ptr2Arg <= 0 || nonOverlappingData->ptr2Arg > args.size())
    3980           0 :                     continue;
    3981             : 
    3982         910 :                 const Token *ptr1 = args[nonOverlappingData->ptr1Arg - 1];
    3983         910 :                 if (ptr1->hasKnownIntValue() && ptr1->getKnownIntValue() == 0)
    3984         137 :                     continue;
    3985             : 
    3986         773 :                 const Token *ptr2 = args[nonOverlappingData->ptr2Arg - 1];
    3987         773 :                 if (ptr2->hasKnownIntValue() && ptr2->getKnownIntValue() == 0)
    3988          79 :                     continue;
    3989             : 
    3990             :                 // TODO: nonOverlappingData->strlenArg
    3991         694 :                 const int sizeArg = std::max(nonOverlappingData->sizeArg, nonOverlappingData->countArg);
    3992         694 :                 if (sizeArg <= 0 || sizeArg > args.size()) {
    3993         269 :                     if (nonOverlappingData->sizeArg == -1) {
    3994         269 :                         ErrorPath errorPath;
    3995         269 :                         constexpr bool macro = true;
    3996         269 :                         constexpr bool pure = true;
    3997         269 :                         constexpr bool follow = true;
    3998         269 :                         if (!isSameExpression(macro, ptr1, ptr2, *mSettings, pure, follow, &errorPath))
    3999         247 :                             continue;
    4000          22 :                         overlappingWriteFunction(tok);
    4001             :                     }
    4002          22 :                     continue;
    4003             :                 }
    4004         425 :                 const bool isCountArg = nonOverlappingData->countArg > 0;
    4005         425 :                 if (!args[sizeArg-1]->hasKnownIntValue())
    4006         260 :                     continue;
    4007         165 :                 MathLib::bigint sizeValue = args[sizeArg-1]->getKnownIntValue();
    4008             :                 const Token *buf1, *buf2;
    4009             :                 MathLib::bigint offset1, offset2;
    4010         165 :                 if (!getBufAndOffset(ptr1, buf1, &offset1, *mSettings, isCountArg ? &sizeValue : nullptr))
    4011           0 :                     continue;
    4012         165 :                 if (!getBufAndOffset(ptr2, buf2, &offset2, *mSettings))
    4013           1 :                     continue;
    4014             : 
    4015         164 :                 if (offset1 < offset2 && offset1 + sizeValue <= offset2)
    4016          11 :                     continue;
    4017         153 :                 if (offset2 < offset1 && offset2 + sizeValue <= offset1)
    4018           2 :                     continue;
    4019             : 
    4020         151 :                 ErrorPath errorPath;
    4021         151 :                 constexpr bool macro = true;
    4022         151 :                 constexpr bool pure = true;
    4023         151 :                 constexpr bool follow = true;
    4024         151 :                 if (!isSameExpression(macro, buf1, buf2, *mSettings, pure, follow, &errorPath))
    4025          92 :                     continue;
    4026          59 :                 overlappingWriteFunction(tok);
    4027             :             }
    4028             :         }
    4029             :     }
    4030        3807 : }
    4031             : 
    4032           5 : void CheckOther::overlappingWriteUnion(const Token *tok)
    4033             : {
    4034           5 :     reportError(tok, Severity::error, "overlappingWriteUnion", "Overlapping read/write of union is undefined behavior");
    4035           5 : }
    4036             : 
    4037          85 : void CheckOther::overlappingWriteFunction(const Token *tok)
    4038             : {
    4039          85 :     const std::string &funcname = tok ? tok->str() : emptyString;
    4040          85 :     reportError(tok, Severity::error, "overlappingWriteFunction", "Overlapping read/write in " + funcname + "() is undefined behavior");
    4041          85 : }

Generated by: LCOV version 1.14