Cppcheck
checkother.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 
00020 //---------------------------------------------------------------------------
00021 #include "checkother.h"
00022 #include "mathlib.h"
00023 #include "symboldatabase.h"
00024 
00025 #include <cmath> // fabs()
00026 #include <stack>
00027 #include <algorithm> // find_if()
00028 //---------------------------------------------------------------------------
00029 
00030 // Register this check class (by creating a static instance of it)
00031 namespace {
00032     CheckOther instance;
00033 }
00034 
00035 //----------------------------------------------------------------------------------
00036 // The return value of fgetc(), getc(), ungetc(), getchar() etc. is an integer value.
00037 // If this return value is stored in a character variable and then compared
00038 // to compared to EOF, which is an integer, the comparison maybe be false.
00039 //
00040 // Reference:
00041 // - Ticket #160
00042 // - http://www.cplusplus.com/reference/cstdio/fgetc/
00043 // - http://www.cplusplus.com/reference/cstdio/getc/
00044 // - http://www.cplusplus.com/reference/cstdio/getchar/
00045 // - http://www.cplusplus.com/reference/cstdio/ungetc/ ....
00046 //----------------------------------------------------------------------------------
00047 void CheckOther::checkCastIntToCharAndBack()
00048 {
00049     if (!_settings->isEnabled("warning"))
00050         return;
00051 
00052     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00053     const std::size_t functions = symbolDatabase->functionScopes.size();
00054     for (std::size_t i = 0; i < functions; ++i) {
00055         const Scope * scope = symbolDatabase->functionScopes[i];
00056         std::map<unsigned int, std::string> vars;
00057         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00058             if (Token::Match(tok, "%var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (")) {
00059                 const Variable *var = tok->variable();
00060                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
00061                     vars[tok->varId()] = tok->strAt(2);
00062                 }
00063             } else if (Token::Match(tok, "EOF %comp% ( %var% = fclose|fflush|fputc|fputs|fscanf|getchar|getc|fgetc|putchar|putc|puts|scanf|sscanf|ungetc (")) {
00064                 tok = tok->tokAt(3);
00065                 if (tok && tok->varId()) {
00066                     const Variable *var = tok->variable();
00067                     if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
00068                         checkCastIntToCharAndBackError(tok, tok->strAt(2));
00069                     }
00070                 }
00071             } else if (Token::Match(tok, "EOF %comp% ( %var% = std :: cin . get (") || Token::Match(tok, "EOF %comp% ( %var% = cin . get (")) {
00072                 tok = tok->tokAt(3);
00073                 if (tok && tok->varId()) {
00074                     const Variable *var = tok->variable();
00075                     if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
00076                         checkCastIntToCharAndBackError(tok, "cin.get");
00077                     }
00078                 }
00079             } else if (Token::Match(tok, "%var% = std :: cin . get (") || Token::Match(tok, "%var% = cin . get (")) {
00080                 const Variable *var = tok->variable();
00081                 if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
00082                     vars[tok->varId()] = "cin.get";
00083                 }
00084             }
00085             if (Token::Match(tok, "%var% %comp% EOF")) {
00086                 if (vars.find(tok->varId()) != vars.end()) {
00087                     checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
00088                 }
00089             } else if (Token::Match(tok, "EOF %comp% %var%")) {
00090                 tok = tok->tokAt(2);
00091                 if (vars.find(tok->varId()) != vars.end()) {
00092                     checkCastIntToCharAndBackError(tok, vars[tok->varId()]);
00093                 }
00094             }
00095         }
00096     }
00097 }
00098 
00099 void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName)
00100 {
00101     reportError(
00102         tok,
00103         Severity::warning,
00104         "checkCastIntToCharAndBack",
00105         "Storing "+ strFunctionName +"() return value in char variable and then comparing with EOF.\n"
00106         "When saving "+ strFunctionName +"() return value in char variable there is loss of precision. "
00107         " When "+ strFunctionName +"() returns EOF this value is truncated. Comparing the char "
00108         "variable with EOF can have unexpected results. For instance a loop \"while (EOF != (c = "+ strFunctionName +"());\" "
00109         "loops forever on some compilers/platforms and on other compilers/platforms it will stop "
00110         "when the file contains a matching character."
00111     );
00112 }
00113 
00114 //---------------------------------------------------------------------------
00115 //---------------------------------------------------------------------------
00116 void CheckOther::checkIncrementBoolean()
00117 {
00118     if (!_settings->isEnabled("style"))
00119         return;
00120 
00121     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00122     const std::size_t functions = symbolDatabase->functionScopes.size();
00123     for (std::size_t i = 0; i < functions; ++i) {
00124         const Scope * scope = symbolDatabase->functionScopes[i];
00125         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00126             if (Token::Match(tok, "%var% ++")) {
00127                 if (tok->varId()) {
00128                     const Variable *var = tok->variable();
00129 
00130                     if (var && var->typeEndToken()->str() == "bool")
00131                         incrementBooleanError(tok);
00132                 }
00133             }
00134         }
00135     }
00136 }
00137 
00138 void CheckOther::incrementBooleanError(const Token *tok)
00139 {
00140     reportError(
00141         tok,
00142         Severity::style,
00143         "incrementboolean",
00144         "Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n"
00145         "The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true. You should assign it the value 'true' instead."
00146     );
00147 }
00148 
00149 //---------------------------------------------------------------------------
00150 //---------------------------------------------------------------------------
00151 void CheckOther::clarifyCalculation()
00152 {
00153     if (!_settings->isEnabled("style"))
00154         return;
00155 
00156     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00157     const std::size_t functions = symbolDatabase->functionScopes.size();
00158     for (std::size_t i = 0; i < functions; ++i) {
00159         const Scope * scope = symbolDatabase->functionScopes[i];
00160         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00161             if (tok->str() == "?") {
00162                 // condition
00163                 const Token *cond = tok->previous();
00164                 if (cond->isName() || cond->isNumber())
00165                     cond = cond->previous();
00166                 else if (cond->str() == ")")
00167                     cond = cond->link()->previous();
00168                 else
00169                     continue;
00170 
00171                 if (cond && cond->str() == "!")
00172                     cond = cond->previous();
00173 
00174                 if (!cond)
00175                     continue;
00176 
00177                 // calculation
00178                 if (!cond->isArithmeticalOp())
00179                     continue;
00180 
00181                 const std::string &op = cond->str();
00182                 cond = cond->previous();
00183 
00184                 // skip previous multiplications..
00185                 while (cond && cond->previous()) {
00186                     if ((cond->isName() || cond->isNumber()) && cond->previous()->str() == "*")
00187                         cond = cond->tokAt(-2);
00188                     else if (cond->str() == ")")
00189                         cond = cond->link()->previous();
00190                     else
00191                         break;
00192                 }
00193 
00194                 if (!cond)
00195                     continue;
00196 
00197                 // first multiplication operand
00198                 if (cond->str() == ")") {
00199                     clarifyCalculationError(cond, op);
00200                 } else if (cond->isName() || cond->isNumber()) {
00201                     if (Token::Match(cond->previous(),"return|=|+|-|,|(") || cond->strAt(-1) == op)
00202                         clarifyCalculationError(cond, op);
00203                 }
00204             }
00205         }
00206     }
00207 }
00208 
00209 void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op)
00210 {
00211     // suspicious calculation
00212     const std::string calc("'a" + op + "b?c:d'");
00213 
00214     // recommended calculation #1
00215     const std::string s1("'(a" + op + "b)?c:d'");
00216 
00217     // recommended calculation #2
00218     const std::string s2("'a" + op + "(b?c:d)'");
00219 
00220     reportError(tok,
00221                 Severity::style,
00222                 "clarifyCalculation",
00223                 "Clarify calculation precedence for '" + op + "' and '?'.\n"
00224                 "Suspicious calculation. Please use parentheses to clarify the code. "
00225                 "The code '" + calc + "' should be written as either '" + s1 + "' or '" + s2 + "'.");
00226 }
00227 
00228 //---------------------------------------------------------------------------
00229 // Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
00230 // Clarify condition '(a & b == c)' into '((a & b) == c)' or '(a & (b == c))'
00231 //---------------------------------------------------------------------------
00232 void CheckOther::clarifyCondition()
00233 {
00234     if (!_settings->isEnabled("style"))
00235         return;
00236 
00237     const bool isC = _tokenizer->isC();
00238 
00239     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00240     const std::size_t functions = symbolDatabase->functionScopes.size();
00241     for (std::size_t i = 0; i < functions; ++i) {
00242         const Scope * scope = symbolDatabase->functionScopes[i];
00243         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00244             if (Token::Match(tok, "( %var% [=&|^]")) {
00245                 for (const Token *tok2 = tok->tokAt(3); tok2; tok2 = tok2->next()) {
00246                     if (tok2->str() == "(" || tok2->str() == "[")
00247                         tok2 = tok2->link();
00248                     else if (tok2->type() == Token::eComparisonOp) {
00249                         // This might be a template
00250                         if (!isC && tok2->link())
00251                             break;
00252 
00253                         clarifyConditionError(tok, tok->strAt(2) == "=", false);
00254                         break;
00255                     } else if (!tok2->isName() && !tok2->isNumber() && tok2->str() != ".")
00256                         break;
00257                 }
00258             }
00259         }
00260     }
00261 
00262     // using boolean result in bitwise operation ! x [&|^]
00263     for (std::size_t i = 0; i < functions; ++i) {
00264         const Scope * scope = symbolDatabase->functionScopes[i];
00265         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00266             if (Token::Match(tok, "%comp%|!")) {
00267                 if (tok->link()) // don't write false positives when templates are used
00268                     continue;
00269 
00270                 const Token *tok2 = tok->next();
00271 
00272                 // Todo: There are false positives if '(' if encountered. It
00273                 // is assumed there is something like '(char *)&..' and therefore
00274                 // it bails out.
00275                 if (Token::Match(tok2, "(|&"))
00276                     continue;
00277 
00278                 while (tok2 && (tok2->isName() || tok2->isNumber() || Token::Match(tok2,".|(|["))) {
00279                     if (Token::Match(tok2, "(|["))
00280                         tok2 = tok2->link();
00281                     tok2 = tok2->next();
00282                 }
00283 
00284                 if (Token::Match(tok2, "[&|^]")) {
00285                     // don't write false positives when templates are used
00286                     if (Token::Match(tok2, "&|* ,|>") || Token::simpleMatch(tok2->previous(), "const &"))
00287                         continue;
00288 
00289                     // #3609 - CWinTraits<WS_CHILD|WS_VISIBLE>::..
00290                     if (!isC && Token::Match(tok->previous(), "%var% <")) {
00291                         const Token *tok3 = tok2;
00292                         while (Token::Match(tok3, "[&|^] %var%"))
00293                             tok3 = tok3->tokAt(2);
00294                         if (Token::Match(tok3, ",|>"))
00295                             continue;
00296                     }
00297 
00298                     clarifyConditionError(tok,false,true);
00299                 }
00300             }
00301         }
00302     }
00303 }
00304 
00305 void CheckOther::clarifyConditionError(const Token *tok, bool assign, bool boolop)
00306 {
00307     std::string errmsg;
00308 
00309     if (assign)
00310         errmsg = "Suspicious condition (assignment + comparison); Clarify expression with parentheses.";
00311 
00312     else if (boolop)
00313         errmsg = "Boolean result is used in bitwise operation. Clarify expression with parentheses.\n"
00314                  "Suspicious expression. Boolean result is used in bitwise operation. The operator '!' "
00315                  "and the comparison operators have higher precedence than bitwise operators. "
00316                  "It is recommended that the expression is clarified with parentheses.";
00317     else
00318         errmsg = "Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses.\n"
00319                  "Suspicious condition. Comparison operators have higher precedence than bitwise operators. "
00320                  "Please clarify the condition with parentheses.";
00321 
00322     reportError(tok,
00323                 Severity::style,
00324                 "clarifyCondition",
00325                 errmsg);
00326 }
00327 
00328 //---------------------------------------------------------------------------
00329 // Clarify (meaningless) statements like *foo++; with parentheses.
00330 //---------------------------------------------------------------------------
00331 void CheckOther::clarifyStatement()
00332 {
00333     if (!_settings->isEnabled("warning"))
00334         return;
00335 
00336     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00337     const std::size_t functions = symbolDatabase->functionScopes.size();
00338     for (std::size_t i = 0; i < functions; ++i) {
00339         const Scope * scope = symbolDatabase->functionScopes[i];
00340         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
00341             if (Token::Match(tok, "* %var%")) {
00342                 const Token *tok2=tok->previous();
00343 
00344                 while (tok2 && tok2->str() == "*")
00345                     tok2=tok2->previous();
00346 
00347                 if (Token::Match(tok2, "[{};]")) {
00348                     tok = tok->tokAt(2);
00349                     for (;;) {
00350                         if (tok->str() == "[")
00351                             tok = tok->link()->next();
00352 
00353                         if (Token::Match(tok, ".|:: %var%")) {
00354                             if (tok->strAt(2) == "(")
00355                                 tok = tok->linkAt(2)->next();
00356                             else
00357                                 tok = tok->tokAt(2);
00358                         } else
00359                             break;
00360                     }
00361                     if (Token::Match(tok, "++|-- [;,]"))
00362                         clarifyStatementError(tok);
00363                 }
00364             }
00365         }
00366     }
00367 }
00368 
00369 void CheckOther::clarifyStatementError(const Token *tok)
00370 {
00371     reportError(tok, Severity::warning, "clarifyStatement", "Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n"
00372                 "A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. "
00373                 "Thus, the dereference is meaningless. Did you intend to write '(*A)++;'?");
00374 }
00375 
00376 //---------------------------------------------------------------------------
00377 // if (bool & bool) -> if (bool && bool)
00378 // if (bool | bool) -> if (bool || bool)
00379 //---------------------------------------------------------------------------
00380 void CheckOther::checkBitwiseOnBoolean()
00381 {
00382     if (!_settings->isEnabled("style"))
00383         return;
00384 
00385     // danmar: this is inconclusive because I don't like that there are
00386     //         warnings for calculations. Example: set_flag(a & b);
00387     if (!_settings->inconclusive)
00388         return;
00389 
00390     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00391     const std::size_t functions = symbolDatabase->functionScopes.size();
00392     for (std::size_t i = 0; i < functions; ++i) {
00393         const Scope * scope = symbolDatabase->functionScopes[i];
00394         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00395             if (Token::Match(tok, "(|.|return|&&|%oror%|throw|, %var% [&|]")) {
00396                 const Variable *var = tok->next()->variable();
00397                 if (var && var->typeEndToken()->str() == "bool") {
00398                     bitwiseOnBooleanError(tok->next(), var->name(), tok->strAt(2) == "&" ? "&&" : "||");
00399                     tok = tok->tokAt(2);
00400                 }
00401             } else if (Token::Match(tok, "[&|] %var% )|.|return|&&|%oror%|throw|,") && (!tok->previous() || !tok->previous()->isExtendedOp() || tok->strAt(-1) == ")" || tok->strAt(-1) == "]")) {
00402                 const Variable *var = tok->next()->variable();
00403                 if (var && var->typeEndToken()->str() == "bool") {
00404                     bitwiseOnBooleanError(tok->next(), var->name(), tok->str() == "&" ? "&&" : "||");
00405                     tok = tok->tokAt(2);
00406                 }
00407             }
00408         }
00409     }
00410 }
00411 
00412 void CheckOther::bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op)
00413 {
00414     reportError(tok, Severity::style, "bitwiseOnBoolean",
00415                 "Boolean variable '" + varname + "' is used in bitwise operation. Did you mean '" + op + "'?", true);
00416 }
00417 
00418 void CheckOther::checkSuspiciousSemicolon()
00419 {
00420     if (!_settings->inconclusive || !_settings->isEnabled("warning"))
00421         return;
00422 
00423     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
00424 
00425     // Look for "if(); {}", "for(); {}" or "while(); {}"
00426     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
00427         if (i->type == Scope::eIf || i->type == Scope::eElse || i->type == Scope::eElseIf || i->type == Scope::eWhile || i->type == Scope::eFor) {
00428             // Ensure the semicolon is at the same line number as the if/for/while statement
00429             // and the {..} block follows it without an extra empty line.
00430             if (Token::simpleMatch(i->classStart, "{ ; } {") &&
00431                 i->classStart->previous()->linenr() == i->classStart->tokAt(2)->linenr()
00432                 && i->classStart->linenr()+1 >= i->classStart->tokAt(3)->linenr()) {
00433                 SuspiciousSemicolonError(i->classDef);
00434             }
00435         }
00436     }
00437 }
00438 
00439 void CheckOther::SuspiciousSemicolonError(const Token* tok)
00440 {
00441     reportError(tok, Severity::warning, "suspiciousSemicolon",
00442                 "Suspicious use of ; at the end of '" + (tok ? tok->str() : std::string()) + "' statement.", true);
00443 }
00444 
00445 
00446 //---------------------------------------------------------------------------
00447 //---------------------------------------------------------------------------
00448 void CheckOther::warningOldStylePointerCast()
00449 {
00450     // Only valid on C++ code
00451     if (!_settings->isEnabled("style") || !_tokenizer->isCPP())
00452         return;
00453 
00454     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
00455         // Old style pointer casting..
00456         if (!Token::Match(tok, "( const| %type% * ) (| %var%") &&
00457             !Token::Match(tok, "( const| %type% * ) (| new"))
00458             continue;
00459 
00460         if (tok->strAt(1) == "const")
00461             tok = tok->next();
00462 
00463         if (tok->strAt(4) == "const")
00464             continue;
00465 
00466         // Is "type" a class?
00467         const std::string pattern("class|struct " + tok->strAt(1));
00468         if (Token::findmatch(_tokenizer->tokens(), pattern.c_str(), tok))
00469             cstyleCastError(tok);
00470     }
00471 }
00472 
00473 void CheckOther::cstyleCastError(const Token *tok)
00474 {
00475     reportError(tok, Severity::style, "cstyleCast", "C-style pointer casting");
00476 }
00477 
00478 //---------------------------------------------------------------------------
00479 // float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
00480 //---------------------------------------------------------------------------
00481 
00482 static std::string analyzeType(const Token* tok)
00483 {
00484     if (tok->str() == "double") {
00485         if (tok->isLong())
00486             return "long double";
00487         else
00488             return "double";
00489     }
00490     if (tok->str() == "float")
00491         return "float";
00492     if (Token::Match(tok, "int|long|short|char|size_t"))
00493         return "integer";
00494     return "";
00495 }
00496 
00497 void CheckOther::invalidPointerCast()
00498 {
00499     if (!_settings->isEnabled("warning") && !_settings->isEnabled("portability"))
00500         return;
00501 
00502     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
00503     const std::size_t functions = symbolDatabase->functionScopes.size();
00504     for (std::size_t i = 0; i < functions; ++i) {
00505         const Scope * scope = symbolDatabase->functionScopes[i];
00506         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00507             const Token* toTok = 0;
00508             const Token* nextTok = 0;
00509             // Find cast
00510             if (Token::Match(tok, "( const| %type% const| * )") ||
00511                 Token::Match(tok, "( const| %type% %type% const| * )")) {
00512                 toTok = tok->next();
00513                 nextTok = tok->link()->next();
00514                 if (nextTok && nextTok->str() == "(")
00515                     nextTok = nextTok->next();
00516             } else if (Token::Match(tok, "reinterpret_cast < const| %type% const| * > (") ||
00517                        Token::Match(tok, "reinterpret_cast < const| %type% %type% const| * > (")) {
00518                 nextTok = tok->tokAt(5);
00519                 while (nextTok->str() != "(")
00520                     nextTok = nextTok->next();
00521                 nextTok = nextTok->next();
00522                 toTok = tok->tokAt(2);
00523             }
00524             if (toTok && toTok->str() == "const")
00525                 toTok = toTok->next();
00526 
00527             if (!nextTok || !toTok || !toTok->isStandardType())
00528                 continue;
00529 
00530             // Find casted variable
00531             const Variable *var = 0;
00532             bool allocation = false;
00533             bool ref = false;
00534             if (Token::Match(nextTok, "new %type%"))
00535                 allocation = true;
00536             else if (Token::Match(nextTok, "%var% !!["))
00537                 var = nextTok->variable();
00538             else if (Token::Match(nextTok, "& %var%") && !Token::Match(nextTok->tokAt(2), "(|[")) {
00539                 var = nextTok->next()->variable();
00540                 ref = true;
00541             }
00542 
00543             const Token* fromTok = 0;
00544 
00545             if (allocation) {
00546                 fromTok = nextTok->next();
00547             } else {
00548                 if (!var || (!ref && !var->isPointer() && !var->isArray()) || (ref && (var->isPointer() || var->isArray())))
00549                     continue;
00550                 fromTok = var->typeStartToken();
00551             }
00552 
00553             while (Token::Match(fromTok, "static|const"))
00554                 fromTok = fromTok->next();
00555             if (!fromTok->isStandardType())
00556                 continue;
00557 
00558             std::string fromType = analyzeType(fromTok);
00559             std::string toType = analyzeType(toTok);
00560             if (fromType != toType && !fromType.empty() && !toType.empty() && (toType != "integer" || _settings->isEnabled("portability")) && (toTok->str() != "char" || _settings->inconclusive))
00561                 invalidPointerCastError(tok, fromType, toType, toTok->str() == "char");
00562         }
00563     }
00564 }
00565 
00566 void CheckOther::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive)
00567 {
00568     if (to == "integer") { // If we cast something to int*, this can be useful to play with its binary data representation
00569         if (!inconclusive)
00570             reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + "* to integer* is not portable due to different binary data representations on different platforms.");
00571         else
00572             reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + "* to char* is not portable due to different binary data representations on different platforms.", true);
00573     } else
00574         reportError(tok, Severity::warning, "invalidPointerCast", "Casting between " + from + "* and " + to + "* which have an incompatible binary data representation.");
00575 }
00576 
00577 //---------------------------------------------------------------------------
00578 //---------------------------------------------------------------------------
00579 void CheckOther::checkSizeofForNumericParameter()
00580 {
00581     if (!_settings->isEnabled("warning"))
00582         return;
00583 
00584     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00585     const std::size_t functions = symbolDatabase->functionScopes.size();
00586     for (std::size_t i = 0; i < functions; ++i) {
00587         const Scope * scope = symbolDatabase->functionScopes[i];
00588         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00589             if (Token::Match(tok, "sizeof ( %num% )") ||
00590                 Token::Match(tok, "sizeof %num%")) {
00591                 sizeofForNumericParameterError(tok);
00592             }
00593         }
00594     }
00595 }
00596 
00597 void CheckOther::sizeofForNumericParameterError(const Token *tok)
00598 {
00599     reportError(tok, Severity::warning,
00600                 "sizeofwithnumericparameter", "Suspicious usage of 'sizeof' with a numeric constant as parameter.\n"
00601                 "It is unusual to use a constant value with sizeof. For example, 'sizeof(10)'"
00602                 " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. 'sizeof('A')'"
00603                 " and 'sizeof(char)' can return different results.");
00604 }
00605 
00606 //---------------------------------------------------------------------------
00607 // This check detects errors on POSIX systems, when a pipe command called
00608 // with a wrong dimensioned file descriptor array. The pipe command requires
00609 // exactly an integer array of dimension two as parameter.
00610 //
00611 // References:
00612 //  - http://linux.die.net/man/2/pipe
00613 //  - ticket #3521
00614 //---------------------------------------------------------------------------
00615 void CheckOther::checkPipeParameterSize()
00616 {
00617     if (!_settings->standards.posix)
00618         return;
00619 
00620     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00621     const std::size_t functions = symbolDatabase->functionScopes.size();
00622     for (std::size_t i = 0; i < functions; ++i) {
00623         const Scope * scope = symbolDatabase->functionScopes[i];
00624         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00625             if (Token::Match(tok, "pipe ( %var% )") ||
00626                 Token::Match(tok, "pipe2 ( %var% ,")) {
00627                 const Token * const varTok = tok->tokAt(2);
00628 
00629                 const Variable *var = varTok->variable();
00630                 MathLib::bigint dim;
00631                 if (var && (var->isArray() || var->isPointer()) && ((dim=var->dimension(0U)) < 2)) {
00632                     const std::string strDim = MathLib::longToString(dim);
00633                     checkPipeParameterSizeError(varTok,varTok->str(), strDim);
00634                 }
00635             }
00636         }
00637     }
00638 }
00639 
00640 void CheckOther::checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim)
00641 {
00642     reportError(tok, Severity::error,
00643                 "wrongPipeParameterSize", "Buffer '" + strVarName + "' must have size of 2 integers if used as parameter of pipe().\n"
00644                 "The pipe()/pipe2() system command takes an argument, which is an array of exactly two integers.\n"
00645                 "The variable '" + strVarName + "' is an array of size " + strDim + ", which does not match.");
00646 }
00647 
00648 //-----------------------------------------------------------------------------
00649 // check usleep(), which is allowed to be called with in a range of [0,999999]
00650 //
00651 // Reference:
00652 // - http://man7.org/linux/man-pages/man3/usleep.3.html
00653 //-----------------------------------------------------------------------------
00654 void CheckOther::checkSleepTimeInterval()
00655 {
00656     if (!_settings->standards.posix)
00657         return;
00658 
00659     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00660     const std::size_t functions = symbolDatabase->functionScopes.size();
00661     for (std::size_t i = 0; i < functions; ++i) {
00662         const Scope * scope = symbolDatabase->functionScopes[i];
00663         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00664             if (Token::Match(tok, "usleep ( %num% )")) {
00665                 const Token * const numTok = tok->tokAt(2);
00666                 MathLib::bigint value = MathLib::toLongNumber(numTok->str());
00667                 if (value > 999999) { // less than 1 million
00668                     checkSleepTimeError(numTok, numTok->str());
00669                 }
00670             }
00671         }
00672     }
00673 }
00674 
00675 void CheckOther::checkSleepTimeError(const Token *tok, const std::string &strDim)
00676 {
00677     reportError(tok, Severity::error,
00678                 "tooBigSleepTime", "The argument of usleep must be less than 1000000.\n"
00679                 "The argument of usleep must be less than 1000000, but " + strDim + " is provided.");
00680 }
00681 
00682 //---------------------------------------------------------------------------
00683 //---------------------------------------------------------------------------
00684 void CheckOther::checkSizeofForArrayParameter()
00685 {
00686     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00687     const std::size_t functions = symbolDatabase->functionScopes.size();
00688     for (std::size_t i = 0; i < functions; ++i) {
00689         const Scope * scope = symbolDatabase->functionScopes[i];
00690         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00691             if (Token::Match(tok, "sizeof ( %var% )") ||
00692                 Token::Match(tok, "sizeof %var% !![")) {
00693                 const Token* varTok = tok->next();
00694                 if (varTok->str() == "(") {
00695                     varTok = varTok->next();
00696                 }
00697                 if (varTok->varId() > 0) {
00698                     const Variable *var = varTok->variable();
00699                     if (var && var->isArray() && var->isArgument()) {
00700                         sizeofForArrayParameterError(tok);
00701                     }
00702                 }
00703             }
00704         }
00705     }
00706 }
00707 
00708 void CheckOther::sizeofForArrayParameterError(const Token *tok)
00709 {
00710     reportError(tok, Severity::error,
00711                 "sizeofwithsilentarraypointer", "Using 'sizeof' on array given as function argument "
00712                 "returns size of a pointer.\n"
00713                 "Using 'sizeof' for array given as function argument returns the size of a pointer. "
00714                 "It does not return the size of the whole array in bytes as might be "
00715                 "expected. For example, this code:\n"
00716                 "     int f(char a[100]) {\n"
00717                 "         return sizeof(a);\n"
00718                 "     }\n"
00719                 "returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
00720                 "size of the array in bytes)."
00721                );
00722 }
00723 
00724 void CheckOther::checkSizeofForPointerSize()
00725 {
00726     if (!_settings->isEnabled("warning"))
00727         return;
00728 
00729     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00730     const std::size_t functions = symbolDatabase->functionScopes.size();
00731     for (std::size_t i = 0; i < functions; ++i) {
00732         const Scope * scope = symbolDatabase->functionScopes[i];
00733         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
00734             const Token *tokVar;
00735             const Token *variable;
00736             const Token *variable2 = 0;
00737 
00738             // Find any function that may use sizeof on a pointer
00739             // Once leaving those tests, it is mandatory to have:
00740             // - variable matching the used pointer
00741             // - tokVar pointing on the argument where sizeof may be used
00742             if (Token::Match(tok, "[*;{}] %var% = malloc|alloca (")) {
00743                 variable = tok->next();
00744                 tokVar = tok->tokAt(5);
00745 
00746             } else if (Token::Match(tok, "[*;{}] %var% = calloc (")) {
00747                 variable = tok->next();
00748                 tokVar = tok->tokAt(5)->nextArgument();
00749 
00750             } else if (Token::simpleMatch(tok, "memset (")) {
00751                 variable = tok->tokAt(2);
00752                 tokVar = variable->tokAt(2)->nextArgument();
00753 
00754                 // The following tests can be inconclusive in case the variable in sizeof
00755                 // is constant string by intention
00756             } else if (!_settings->inconclusive) {
00757                 continue;
00758 
00759             } else if (Token::Match(tok, "memcpy|memcmp|memmove|strncpy|strncmp|strncat (")) {
00760                 variable = tok->tokAt(2);
00761                 variable2 = variable->nextArgument();
00762                 tokVar = variable2->nextArgument();
00763 
00764             } else {
00765                 continue;
00766             }
00767 
00768             // Ensure the variables are in the symbol database
00769             // Also ensure the variables are pointers
00770             // Only keep variables which are pointers
00771             const Variable *var = variable->variable();
00772             if (!var || !var->isPointer() || var->isArray()) {
00773                 variable = 0;
00774             }
00775 
00776             if (variable2) {
00777                 var = variable2->variable();
00778                 if (!var || !var->isPointer() || var->isArray()) {
00779                     variable2 = 0;
00780                 }
00781             }
00782 
00783             // If there are no pointer variable at this point, there is
00784             // no need to continue
00785             if (variable == 0 && variable2 == 0) {
00786                 continue;
00787             }
00788 
00789             // Jump to the next sizeof token in the function and in the parameter
00790             // This is to allow generic operations with sizeof
00791             for (; tokVar && tokVar->str() != ")" && tokVar->str() != "," && tokVar->str() != "sizeof"; tokVar = tokVar->next()) {}
00792 
00793             // Now check for the sizeof usage. Once here, everything using sizeof(varid) or sizeof(&varid)
00794             // looks suspicious
00795             // Do it for first variable
00796             if (variable && (Token::Match(tokVar, "sizeof ( &| %varid% )", variable->varId()) ||
00797                              Token::Match(tokVar, "sizeof &| %varid%", variable->varId()))) {
00798                 sizeofForPointerError(variable, variable->str());
00799             } else if (variable2 && (Token::Match(tokVar, "sizeof ( &| %varid% )", variable2->varId()) ||
00800                                      Token::Match(tokVar, "sizeof &| %varid%", variable2->varId()))) {
00801                 sizeofForPointerError(variable2, variable2->str());
00802             }
00803         }
00804     }
00805 }
00806 
00807 void CheckOther::sizeofForPointerError(const Token *tok, const std::string &varname)
00808 {
00809     reportError(tok, Severity::warning, "pointerSize",
00810                 "Size of pointer '" + varname + "' used instead of size of its data.\n"
00811                 "Size of pointer '" + varname + "' used instead of size of its data. "
00812                 "This is likely to lead to a buffer overflow. You probably intend to "
00813                 "write 'sizeof(*" + varname + ")'.", true);
00814 }
00815 
00816 //---------------------------------------------------------------------------
00817 // Detect redundant assignments: x = 0; x = 4;
00818 //---------------------------------------------------------------------------
00819 
00820 static bool nonLocal(const Variable* var)
00821 {
00822     return !var || (!var->isLocal() && !var->isArgument()) || var->isStatic() || var->isReference();
00823 }
00824 
00825 static void eraseNotLocalArg(std::map<unsigned int, const Token*>& container, const SymbolDatabase* symbolDatabase)
00826 {
00827     for (std::map<unsigned int, const Token*>::iterator i = container.begin(); i != container.end();) {
00828         const Variable* var = symbolDatabase->getVariableFromVarId(i->first);
00829         if (!var || nonLocal(var)) {
00830             container.erase(i++);
00831             if (i == container.end())
00832                 break;
00833         } else
00834             ++i;
00835     }
00836 }
00837 
00838 void CheckOther::checkRedundantAssignment()
00839 {
00840     bool performance = _settings->isEnabled("performance");
00841     bool warning = _settings->isEnabled("warning");
00842     if (!warning && !performance)
00843         return;
00844 
00845     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
00846 
00847     for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
00848         if (!scope->isExecutable())
00849             continue;
00850 
00851         std::map<unsigned int, const Token*> varAssignments;
00852         std::map<unsigned int, const Token*> memAssignments;
00853         const Token* writtenArgumentsEnd = 0;
00854 
00855         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
00856             if (tok == writtenArgumentsEnd)
00857                 writtenArgumentsEnd = 0;
00858 
00859             if (tok->str() == "{" && tok->strAt(-1) != "{" && tok->strAt(-1) != "=" && tok->strAt(-4) != "case" && tok->strAt(-3) != "default") { // conditional or non-executable inner scope: Skip it and reset status
00860                 tok = tok->link();
00861                 varAssignments.clear();
00862                 memAssignments.clear();
00863             } else if (Token::Match(tok, "for|if|while (")) {
00864                 tok = tok->linkAt(1);
00865             } else if (Token::Match(tok, "break|return|continue|throw|goto")) {
00866                 varAssignments.clear();
00867                 memAssignments.clear();
00868             } else if (tok->type() == Token::eVariable) {
00869                 std::map<unsigned int, const Token*>::iterator it = varAssignments.find(tok->varId());
00870                 if (tok->next()->isAssignmentOp() && Token::Match(tok->previous(), "[;{}]")) { // Assignment
00871                     if (it != varAssignments.end()) {
00872                         bool error = true; // Ensure that variable is not used on right side
00873                         for (const Token* tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
00874                             if (tok2->str() == ";")
00875                                 break;
00876                             else if (tok2->varId() == tok->varId())
00877                                 error = false;
00878                             else if (Token::Match(tok2, "%var% (") && nonLocal(tok->variable())) { // Called function might use the variable
00879                                 const Function* func = symbolDatabase->findFunction(tok2);
00880                                 const Variable* var = tok->variable();
00881                                 if (!var || var->isGlobal() || var->isReference() || ((!func || func->nestedIn) && tok2->strAt(-1) != ".")) // Global variable, or member function
00882                                     error = false;
00883                             }
00884                         }
00885                         if (error) {
00886                             if (scope->type == Scope::eSwitch && Token::findmatch(it->second, "default|case", tok) && warning)
00887                                 redundantAssignmentInSwitchError(it->second, tok, tok->str());
00888                             else if (performance)
00889                                 redundantAssignmentError(it->second, tok, tok->str(), nonLocal(it->second->variable())); // Inconclusive for non-local variables
00890                         }
00891                         it->second = tok;
00892                     }
00893                     if (Token::simpleMatch(tok->tokAt(2), "0 ;"))
00894                         varAssignments.erase(tok->varId());
00895                     else
00896                         varAssignments[tok->varId()] = tok;
00897                     memAssignments.erase(tok->varId());
00898                 } else if (tok->next()->type() == Token::eIncDecOp || (tok->previous()->type() == Token::eIncDecOp && !Token::Match(tok->next(), ".|[|("))) { // Variable incremented/decremented
00899                     varAssignments[tok->varId()] = tok;
00900                     memAssignments.erase(tok->varId());
00901                 } else if (!Token::simpleMatch(tok->tokAt(-2), "sizeof (")) { // Other usage of variable
00902                     if (it != varAssignments.end())
00903                         varAssignments.erase(it);
00904                     if (!writtenArgumentsEnd) // Indicates that we are in the first argument of strcpy/memcpy/... function
00905                         memAssignments.erase(tok->varId());
00906                 }
00907             } else if (Token::Match(tok, "%var% (")) { // Function call. Global variables might be used. Reset their status
00908                 bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat");
00909                 if (memfunc) {
00910                     const Token* param1 = tok->tokAt(2);
00911                     writtenArgumentsEnd = param1->next();
00912                     if (param1->varId() && param1->strAt(1) == "," && !Token::Match(tok, "strcat|strncat|wcscat|wcsncat")) {
00913                         std::map<unsigned int, const Token*>::iterator it = memAssignments.find(param1->varId());
00914                         if (it == memAssignments.end())
00915                             memAssignments[param1->varId()] = tok;
00916                         else {
00917                             if (scope->type == Scope::eSwitch && Token::findmatch(it->second, "default|case", tok) && warning)
00918                                 redundantCopyInSwitchError(it->second, tok, param1->str());
00919                             else if (performance)
00920                                 redundantCopyError(it->second, tok, param1->str());
00921                         }
00922                     }
00923                 } else if (scope->type == Scope::eSwitch) { // Avoid false positives if noreturn function is called in switch
00924                     const Function* func = tok->function();
00925                     if (!func || !func->hasBody) {
00926                         varAssignments.clear();
00927                         memAssignments.clear();
00928                         continue;
00929                     }
00930                     const Token* funcEnd = func->functionScope->classEnd;
00931                     bool noreturn;
00932                     if (!_tokenizer->IsScopeNoReturn(funcEnd, &noreturn) && !noreturn) {
00933                         eraseNotLocalArg(varAssignments, symbolDatabase);
00934                         eraseNotLocalArg(memAssignments, symbolDatabase);
00935                     } else {
00936                         varAssignments.clear();
00937                         memAssignments.clear();
00938                     }
00939                 } else { // Noreturn functions outside switch don't cause problems
00940                     eraseNotLocalArg(varAssignments, symbolDatabase);
00941                     eraseNotLocalArg(memAssignments, symbolDatabase);
00942                 }
00943             }
00944         }
00945     }
00946 }
00947 
00948 void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var)
00949 {
00950     std::list<const Token*> callstack;
00951     callstack.push_back(tok1);
00952     callstack.push_back(tok2);
00953     reportError(callstack, Severity::performance, "redundantCopy",
00954                 "Buffer '" + var + "' is being written before its old content has been used.");
00955 }
00956 
00957 void CheckOther::redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
00958 {
00959     std::list<const Token*> callstack;
00960     callstack.push_back(tok1);
00961     callstack.push_back(tok2);
00962     reportError(callstack, Severity::warning, "redundantCopyInSwitch",
00963                 "Buffer '" + var + "' is being written before its old content has been used. 'break;' missing?");
00964 }
00965 
00966 void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
00967 {
00968     std::list<const Token*> callstack;
00969     callstack.push_back(tok1);
00970     callstack.push_back(tok2);
00971     if (inconclusive)
00972         reportError(callstack, Severity::performance, "redundantAssignment",
00973                     "Variable '" + var + "' is reassigned a value before the old one has been used if variable is no semaphore variable.\n"
00974                     "Variable '" + var + "' 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.", true);
00975     else
00976         reportError(callstack, Severity::performance, "redundantAssignment",
00977                     "Variable '" + var + "' is reassigned a value before the old one has been used.");
00978 }
00979 
00980 void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
00981 {
00982     std::list<const Token*> callstack;
00983     callstack.push_back(tok1);
00984     callstack.push_back(tok2);
00985     reportError(callstack, Severity::warning, "redundantAssignInSwitch",
00986                 "Variable '" + var + "' is reassigned a value before the old one has been used. 'break;' missing?");
00987 }
00988 
00989 
00990 //---------------------------------------------------------------------------
00991 //    switch (x)
00992 //    {
00993 //        case 2:
00994 //            y = a;        // <- this assignment is redundant
00995 //        case 3:
00996 //            y = b;        // <- case 2 falls through and sets y twice
00997 //    }
00998 //---------------------------------------------------------------------------
00999 static inline bool isFunctionOrBreakPattern(const Token *tok)
01000 {
01001     if (Token::Match(tok, "%var% (") || Token::Match(tok, "break|continue|return|exit|goto|throw"))
01002         return true;
01003 
01004     return false;
01005 }
01006 
01007 void CheckOther::checkRedundantAssignmentInSwitch()
01008 {
01009     if (!_settings->isEnabled("warning"))
01010         return;
01011 
01012     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
01013 
01014     // Find the beginning of a switch. E.g.:
01015     //   switch (var) { ...
01016     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
01017         if (i->type != Scope::eSwitch || !i->classStart)
01018             continue;
01019 
01020         // Check the contents of the switch statement
01021         std::map<unsigned int, const Token*> varsWithBitsSet;
01022         std::map<unsigned int, std::string> bitOperations;
01023 
01024         for (const Token *tok2 = i->classStart->next(); tok2 != i->classEnd; tok2 = tok2->next()) {
01025             if (tok2->str() == "{") {
01026                 // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
01027                 //   case 3: b = 1;
01028                 //   case 4: if (a) { b = 2; }    // Doesn't make the b=1 redundant because it's conditional
01029                 if (Token::Match(tok2->previous(), ")|else {") && tok2->link()) {
01030                     const Token* endOfConditional = tok2->link();
01031                     for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) {
01032                         if (tok3->varId() != 0) {
01033                             varsWithBitsSet.erase(tok3->varId());
01034                             bitOperations.erase(tok3->varId());
01035                         } else if (isFunctionOrBreakPattern(tok3)) {
01036                             varsWithBitsSet.clear();
01037                             bitOperations.clear();
01038                         }
01039                     }
01040                     tok2 = endOfConditional;
01041                 }
01042             }
01043 
01044             // Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
01045             //    case 3: b = 1;    // <== redundant
01046             //    case 4: b = 2;
01047 
01048             if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;") && tok2->varId() != 0) {
01049                 varsWithBitsSet.erase(tok2->varId());
01050                 bitOperations.erase(tok2->varId());
01051             }
01052 
01053             // Bitwise operation. Report an error if it's performed twice before a break. E.g.:
01054             //    case 3: b |= 1;    // <== redundant
01055             //    case 4: b |= 1;
01056             else if (Token::Match(tok2->previous(), ";|{|}|: %var% = %var% %or%|& %num% ;") &&
01057                      tok2->varId() != 0 && tok2->varId() == tok2->tokAt(2)->varId()) {
01058                 std::string bitOp = tok2->strAt(3) + tok2->strAt(4);
01059                 std::map<unsigned int, const Token*>::iterator i2 = varsWithBitsSet.find(tok2->varId());
01060 
01061                 // This variable has not had a bit operation performed on it yet, so just make a note of it
01062                 if (i2 == varsWithBitsSet.end()) {
01063                     varsWithBitsSet[tok2->varId()] = tok2;
01064                     bitOperations[tok2->varId()] = bitOp;
01065                 }
01066 
01067                 // The same bit operation has been performed on the same variable twice, so report an error
01068                 else if (bitOperations[tok2->varId()] == bitOp)
01069                     redundantBitwiseOperationInSwitchError(i2->second, i2->second->str());
01070 
01071                 // A different bit operation was performed on the variable, so clear it
01072                 else {
01073                     varsWithBitsSet.erase(tok2->varId());
01074                     bitOperations.erase(tok2->varId());
01075                 }
01076             }
01077 
01078             // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
01079             //    case 3: b = 1;
01080             //    case 4: b++;
01081             else if (tok2->varId() != 0 && tok2->strAt(1) != "|" && tok2->strAt(1) != "&") {
01082                 varsWithBitsSet.erase(tok2->varId());
01083                 bitOperations.erase(tok2->varId());
01084             }
01085 
01086             // Reset our record of assignments if there is a break or function call. E.g.:
01087             //    case 3: b = 1; break;
01088             if (isFunctionOrBreakPattern(tok2)) {
01089                 varsWithBitsSet.clear();
01090                 bitOperations.clear();
01091             }
01092         }
01093     }
01094 }
01095 
01096 void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname)
01097 {
01098     reportError(tok, Severity::warning,
01099                 "redundantBitwiseOperationInSwitch", "Redundant bitwise operation on '" + varname + "' in 'switch' statement. 'break;' missing?");
01100 }
01101 
01102 
01103 //---------------------------------------------------------------------------
01104 //---------------------------------------------------------------------------
01105 void CheckOther::checkSwitchCaseFallThrough()
01106 {
01107     if (!(_settings->isEnabled("style") && _settings->experimental))
01108         return;
01109 
01110     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
01111 
01112     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
01113         if (i->type != Scope::eSwitch || !i->classStart) // Find the beginning of a switch
01114             continue;
01115 
01116         // Check the contents of the switch statement
01117         std::stack<std::pair<Token *, bool> > ifnest;
01118         std::stack<Token *> loopnest;
01119         std::stack<Token *> scopenest;
01120         bool justbreak = true;
01121         bool firstcase = true;
01122         for (const Token *tok2 = i->classStart; tok2 != i->classEnd; tok2 = tok2->next()) {
01123             if (Token::simpleMatch(tok2, "if (")) {
01124                 tok2 = tok2->next()->link()->next();
01125                 if (tok2->link() == NULL) {
01126                     std::ostringstream errmsg;
01127                     errmsg << "unmatched if in switch: " << tok2->linenr();
01128                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01129                     break;
01130                 }
01131                 ifnest.push(std::make_pair(tok2->link(), false));
01132                 justbreak = false;
01133             } else if (Token::simpleMatch(tok2, "while (")) {
01134                 tok2 = tok2->next()->link()->next();
01135                 // skip over "do { } while ( ) ;" case
01136                 if (tok2->str() == "{") {
01137                     if (tok2->link() == NULL) {
01138                         std::ostringstream errmsg;
01139                         errmsg << "unmatched while in switch: " << tok2->linenr();
01140                         reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01141                         break;
01142                     }
01143                     loopnest.push(tok2->link());
01144                 }
01145                 justbreak = false;
01146             } else if (Token::simpleMatch(tok2, "do {")) {
01147                 tok2 = tok2->next();
01148                 if (tok2->link() == NULL) {
01149                     std::ostringstream errmsg;
01150                     errmsg << "unmatched do in switch: " << tok2->linenr();
01151                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01152                     break;
01153                 }
01154                 loopnest.push(tok2->link());
01155                 justbreak = false;
01156             } else if (Token::simpleMatch(tok2, "for (")) {
01157                 tok2 = tok2->next()->link()->next();
01158                 if (tok2->link() == NULL) {
01159                     std::ostringstream errmsg;
01160                     errmsg << "unmatched for in switch: " << tok2->linenr();
01161                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01162                     break;
01163                 }
01164                 loopnest.push(tok2->link());
01165                 justbreak = false;
01166             } else if (Token::simpleMatch(tok2, "switch (")) {
01167                 // skip over nested switch, we'll come to that soon
01168                 tok2 = tok2->next()->link()->next()->link();
01169             } else if (Token::Match(tok2, "break|continue|return|exit|goto|throw")) {
01170                 if (loopnest.empty()) {
01171                     justbreak = true;
01172                 }
01173                 tok2 = Token::findsimplematch(tok2, ";");
01174             } else if (Token::Match(tok2, "case|default")) {
01175                 if (!justbreak && !firstcase) {
01176                     switchCaseFallThrough(tok2);
01177                 }
01178                 tok2 = Token::findsimplematch(tok2, ":");
01179                 justbreak = true;
01180                 firstcase = false;
01181             } else if (tok2->str() == "{") {
01182                 scopenest.push(tok2->link());
01183             } else if (tok2->str() == "}") {
01184                 if (!ifnest.empty() && tok2 == ifnest.top().first) {
01185                     if (tok2->next()->str() == "else") {
01186                         tok2 = tok2->tokAt(2);
01187                         ifnest.pop();
01188                         if (tok2->link() == NULL) {
01189                             std::ostringstream errmsg;
01190                             errmsg << "unmatched if in switch: " << tok2->linenr();
01191                             reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01192                             break;
01193                         }
01194                         ifnest.push(std::make_pair(tok2->link(), justbreak));
01195                         justbreak = false;
01196                     } else {
01197                         justbreak &= ifnest.top().second;
01198                         ifnest.pop();
01199                     }
01200                 } else if (!loopnest.empty() && tok2 == loopnest.top()) {
01201                     loopnest.pop();
01202                 } else if (!scopenest.empty() && tok2 == scopenest.top()) {
01203                     scopenest.pop();
01204                 } else {
01205                     if (!ifnest.empty() || !loopnest.empty() || !scopenest.empty()) {
01206                         std::ostringstream errmsg;
01207                         errmsg << "unexpected end of switch: ";
01208                         errmsg << "ifnest=" << ifnest.size();
01209                         if (!ifnest.empty())
01210                             errmsg << "," << ifnest.top().first->linenr();
01211                         errmsg << ", loopnest=" << loopnest.size();
01212                         if (!loopnest.empty())
01213                             errmsg << "," << loopnest.top()->linenr();
01214                         errmsg << ", scopenest=" << scopenest.size();
01215                         if (!scopenest.empty())
01216                             errmsg << "," << scopenest.top()->linenr();
01217                         reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
01218                     }
01219                     // end of switch block
01220                     break;
01221                 }
01222             } else if (tok2->str() != ";") {
01223                 justbreak = false;
01224             }
01225 
01226         }
01227     }
01228 }
01229 
01230 void CheckOther::switchCaseFallThrough(const Token *tok)
01231 {
01232     reportError(tok, Severity::style,
01233                 "switchCaseFallThrough", "Switch falls through case without comment. 'break;' missing?");
01234 }
01235 
01236 
01237 //---------------------------------------------------------------------------
01238 // Check for statements like case A||B: in switch()
01239 //---------------------------------------------------------------------------
01240 void CheckOther::checkSuspiciousCaseInSwitch()
01241 {
01242     if (!_settings->inconclusive || !_settings->isEnabled("warning"))
01243         return;
01244 
01245     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
01246 
01247     for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
01248         if (i->type != Scope::eSwitch)
01249             continue;
01250 
01251         for (const Token* tok = i->classStart->next(); tok != i->classEnd; tok = tok->next()) {
01252             if (tok->str() == "case") {
01253                 const Token* end = 0;
01254                 for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
01255                     if (tok2->str() == ":") {
01256                         end = tok2;
01257                         break;
01258                     }
01259                     if (Token::Match(tok2, "[?;}{]")) {
01260                         break;
01261                     }
01262                 }
01263 
01264                 if (end) {
01265                     const Token* finding = Token::findmatch(tok->next(), "&&|%oror%", end);
01266                     if (finding)
01267                         suspiciousCaseInSwitchError(tok, finding->str());
01268                 }
01269             }
01270         }
01271     }
01272 }
01273 
01274 void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
01275 {
01276     reportError(tok, Severity::warning, "suspiciousCase",
01277                 "Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n"
01278                 "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?", true);
01279 }
01280 
01281 //---------------------------------------------------------------------------
01282 //    if (x == 1)
01283 //        x == 0;       // <- suspicious equality comparison.
01284 //---------------------------------------------------------------------------
01285 void CheckOther::checkSuspiciousEqualityComparison()
01286 {
01287     if (!_settings->isEnabled("warning"))
01288         return;
01289 
01290     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
01291 
01292         if (Token::simpleMatch(tok, "for (")) {
01293             const Token* const openParen = tok->next();
01294             const Token* const closeParen = tok->linkAt(1);
01295 
01296             // Search for any suspicious equality comparison in the initialization
01297             // or increment-decrement parts of the for() loop.
01298             // For example:
01299             //    for (i == 2; i < 10; i++)
01300             // or
01301             //    for (i = 0; i < 10; i == a)
01302             const Token* tok2 = Token::findmatch(openParen, "[;(] %var% == %any% [;)]", closeParen);
01303             if (tok2 && (tok2 == openParen || tok2->tokAt(4) == closeParen)) {
01304                 suspiciousEqualityComparisonError(tok2->tokAt(2));
01305             }
01306 
01307             // Equality comparisons with 0 are simplified to negation. For instance,
01308             // (x == 0) is simplified to (!x), so also check for suspicious negation
01309             // in the initialization or increment-decrement parts of the for() loop.
01310             // For example:
01311             //    for (!i; i < 10; i++)
01312             const Token* tok3 = Token::findmatch(openParen, "[;(] ! %var% [;)]", closeParen);
01313             if (tok3 && (tok3 == openParen || tok3->tokAt(3) == closeParen)) {
01314                 suspiciousEqualityComparisonError(tok3->tokAt(2));
01315             }
01316 
01317             // Skip over for() loop conditions because "for (;running==1;)"
01318             // is a bit strange, but not necessarily incorrect.
01319             tok = closeParen;
01320         } else if (Token::Match(tok, "[;{}] *| %var% == %any% ;")) {
01321 
01322             // Exclude compound statements surrounded by parentheses, such as
01323             //    printf("%i\n", ({x==0;}));
01324             // because they may appear as an expression in GNU C/C++.
01325             // See http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
01326             const Token* afterStatement = tok->strAt(1) == "*" ? tok->tokAt(6) : tok->tokAt(5);
01327             if (!Token::simpleMatch(afterStatement, "} )"))
01328                 suspiciousEqualityComparisonError(tok->next());
01329         }
01330     }
01331 }
01332 
01333 void CheckOther::suspiciousEqualityComparisonError(const Token* tok)
01334 {
01335     reportError(tok, Severity::warning, "suspiciousEqualityComparison",
01336                 "Found suspicious equality comparison. Did you intend to assign a value instead?", true);
01337 }
01338 
01339 
01340 //---------------------------------------------------------------------------
01341 //    int x = 1;
01342 //    x = x;            // <- redundant assignment to self
01343 //
01344 //    int y = y;        // <- redundant initialization to self
01345 //---------------------------------------------------------------------------
01346 static bool isTypeWithoutSideEffects(const Tokenizer *tokenizer, const Variable* var)
01347 {
01348     return ((var && (!var->isClass() || var->isPointer() || Token::simpleMatch(var->typeStartToken(), "std ::"))) || !tokenizer->isCPP());
01349 }
01350 
01351 static inline const Token *findSelfAssignPattern(const Token *start)
01352 {
01353     return Token::findmatch(start, "%var% = %var% ;|=|)");
01354 }
01355 
01356 void CheckOther::checkSelfAssignment()
01357 {
01358     if (!_settings->isEnabled("warning"))
01359         return;
01360 
01361     const Token *tok = findSelfAssignPattern(_tokenizer->tokens());
01362     while (tok) {
01363         if (Token::Match(tok->previous(), "[;{}.]") &&
01364             tok->varId() && tok->varId() == tok->tokAt(2)->varId() &&
01365             isTypeWithoutSideEffects(_tokenizer, tok->variable())) {
01366             bool err = true;
01367 
01368             // no false positive for 'x = x ? x : 1;'
01369             // it is simplified to 'if (x) { x=x; } else { x=1; }'. The simplification
01370             // always write all tokens on 1 line (even if the statement is several lines), so
01371             // check if the linenr is the same for all the tokens.
01372             if (Token::Match(tok->tokAt(-2), ") { %var% = %var% ; } else { %varid% =", tok->varId())) {
01373                 // Find the 'if' token
01374                 const Token *tokif = tok->linkAt(-2)->previous();
01375 
01376                 // find the '}' that terminates the 'else'-block
01377                 const Token *else_end = tok->linkAt(6);
01378 
01379                 if (tokif && else_end && tokif->linenr() == else_end->linenr())
01380                     err = false;
01381             }
01382 
01383             if (err)
01384                 selfAssignmentError(tok, tok->str());
01385         }
01386 
01387         tok = findSelfAssignPattern(tok->next());
01388     }
01389 }
01390 
01391 void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
01392 {
01393     reportError(tok, Severity::warning,
01394                 "selfAssignment", "Redundant assignment of '" + varname + "' to itself.");
01395 }
01396 
01397 //---------------------------------------------------------------------------
01398 //    int a = 1;
01399 //    assert(a = 2);            // <- assert should not have a side-effect
01400 //---------------------------------------------------------------------------
01401 static inline const Token *findAssertPattern(const Token *start)
01402 {
01403     return Token::findmatch(start, "assert ( %any%");
01404 }
01405 
01406 void CheckOther::checkAssignmentInAssert()
01407 {
01408     if (!_settings->isEnabled("warning"))
01409         return;
01410 
01411     const Token *tok = findAssertPattern(_tokenizer->tokens());
01412     const Token *endTok = tok ? tok->next()->link() : NULL;
01413 
01414     while (tok && endTok) {
01415         for (tok = tok->tokAt(2); tok != endTok; tok = tok->next()) {
01416             if (tok->isName() && (tok->next()->isAssignmentOp() || tok->next()->type() == Token::eIncDecOp))
01417                 assignmentInAssertError(tok, tok->str());
01418             else if (Token::Match(tok, "--|++ %var%"))
01419                 assignmentInAssertError(tok, tok->strAt(1));
01420         }
01421 
01422         tok = findAssertPattern(endTok->next());
01423         endTok = tok ? tok->next()->link() : NULL;
01424     }
01425 }
01426 
01427 void CheckOther::assignmentInAssertError(const Token *tok, const std::string &varname)
01428 {
01429     reportError(tok, Severity::warning,
01430                 "assignmentInAssert", "Assert statement modifies '" + varname + "'.\n"
01431                 "Variable '" + varname + "' is modified insert assert statement. "
01432                 "Assert statements are removed from release builds so the code inside "
01433                 "assert statement is not executed. If the code is needed also in release "
01434                 "builds, this is a bug.");
01435 }
01436 
01437 //---------------------------------------------------------------------------
01438 //    if ((x != 1) || (x != 3))            // expression always true
01439 //    if ((x == 1) && (x == 3))            // expression always false
01440 //    if ((x < 1)  && (x > 3))             // expression always false
01441 //    if ((x > 3)  || (x < 10))            // expression always true
01442 //    if ((x > 5)  && (x != 1))            // second comparison always true
01443 //
01444 //    Check for suspect logic for an expression consisting of 2 comparison
01445 //    expressions with a shared variable and constants and a logical operator
01446 //    between them.
01447 //
01448 //    Suggest a different logical operator when the logical operator between
01449 //    the comparisons is probably wrong.
01450 //
01451 //    Inform that second comparison is always true when first comparison is true.
01452 //---------------------------------------------------------------------------
01453 
01454 enum Position { First, Second, NA };
01455 enum Relation { Equal, NotEqual, Less, LessEqual, More, MoreEqual };
01456 struct Condition {
01457     Position   position;
01458     const char *opTokStr;
01459 };
01460 
01461 static std::string invertOperatorForOperandSwap(std::string s)
01462 {
01463     for (std::string::size_type i = 0; i < s.length(); i++) {
01464         if (s[i] == '>')
01465             s[i] = '<';
01466         else if (s[i] == '<')
01467             s[i] = '>';
01468     }
01469     return s;
01470 }
01471 
01472 static bool analyzeLogicOperatorCondition(const Condition& c1, const Condition& c2,
01473         bool inv1, bool inv2,
01474         bool varFirst1, bool varFirst2,
01475         const std::string& firstConstant, const std::string& secondConstant,
01476         const Token* op1Tok, const Token* op3Tok,
01477         Relation relation)
01478 {
01479     if (!(c1.position == NA || (c1.position == First && varFirst1) || (c1.position == Second && !varFirst1)))
01480         return false;
01481 
01482     if (!(c2.position == NA || (c2.position == First && varFirst2) || (c2.position == Second && !varFirst2)))
01483         return false;
01484 
01485     if (!Token::Match(op1Tok, inv1?invertOperatorForOperandSwap(c1.opTokStr).c_str():c1.opTokStr))
01486         return false;
01487 
01488     if (!Token::Match(op3Tok, inv2?invertOperatorForOperandSwap(c2.opTokStr).c_str():c2.opTokStr))
01489         return false;
01490 
01491     return (relation == Equal     && MathLib::isEqual(firstConstant, secondConstant)) ||
01492            (relation == NotEqual  && MathLib::isNotEqual(firstConstant, secondConstant)) ||
01493            (relation == Less      && MathLib::isLess(firstConstant, secondConstant)) ||
01494            (relation == LessEqual && MathLib::isLessEqual(firstConstant, secondConstant)) ||
01495            (relation == More      && MathLib::isGreater(firstConstant, secondConstant)) ||
01496            (relation == MoreEqual && MathLib::isGreaterEqual(firstConstant, secondConstant));
01497 }
01498 
01499 void CheckOther::checkIncorrectLogicOperator()
01500 {
01501     bool style = _settings->isEnabled("style");
01502     bool warning = _settings->isEnabled("warning");
01503     if (!style && !warning)
01504         return;
01505 
01506     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
01507     const std::size_t functions = symbolDatabase->functionScopes.size();
01508     for (std::size_t ii = 0; ii < functions; ++ii) {
01509         const Scope * scope = symbolDatabase->functionScopes[ii];
01510         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
01511             // Find a pair of comparison expressions with or without parentheses
01512             // with a shared variable and constants and with a logical operator between them.
01513             // e.g. if (x != 3 || x != 4)
01514             const Token *term1Tok = NULL, *term2Tok = NULL;
01515             const Token *op1Tok = NULL, *op2Tok = NULL, *op3Tok = NULL, *nextTok = NULL;
01516 
01517             if (Token::Match(tok, "( %any% %comp% %any% ) &&|%oror%")) {
01518                 term1Tok = tok->next();
01519                 op1Tok = tok->tokAt(2);
01520                 op2Tok = tok->tokAt(5);
01521             } else if (Token::Match(tok, "%any% %comp% %any% &&|%oror%")) {
01522                 term1Tok = tok;
01523                 op1Tok = tok->next();
01524                 op2Tok = tok->tokAt(3);
01525             }
01526             if (op2Tok) {
01527                 if (Token::Match(op2Tok->next(), "( %any% %comp% %any% ) %any%")) {
01528                     term2Tok = op2Tok->tokAt(2);
01529                     op3Tok = op2Tok->tokAt(3);
01530                     nextTok = op2Tok->tokAt(6);
01531                 } else if (Token::Match(op2Tok->next(), "%any% %comp% %any% %any%")) {
01532                     term2Tok = op2Tok->next();
01533                     op3Tok = op2Tok->tokAt(2);
01534                     nextTok = op2Tok->tokAt(4);
01535                 }
01536             }
01537 
01538             if (nextTok) {
01539                 // Find the common variable and the two different-valued constants
01540                 std::string firstConstant, secondConstant;
01541                 bool varFirst1, varFirst2;
01542                 unsigned int varId;
01543                 const Token *var1Tok = NULL, *var2Tok = NULL;
01544                 if (Token::Match(term1Tok, "%var% %any% %num%")) {
01545                     var1Tok = term1Tok;
01546                     varId = var1Tok->varId();
01547                     if (!varId) {
01548                         continue;
01549                     }
01550                     varFirst1 = true;
01551                     firstConstant = term1Tok->strAt(2);
01552                 } else if (Token::Match(term1Tok, "%num% %any% %var%")) {
01553                     var1Tok = term1Tok->tokAt(2);
01554                     varId = var1Tok->varId();
01555                     if (!varId) {
01556                         continue;
01557                     }
01558                     varFirst1 = false;
01559                     firstConstant = term1Tok->str();
01560                 } else {
01561                     continue;
01562                 }
01563 
01564                 if (Token::Match(term2Tok, "%var% %any% %num%")) {
01565                     var2Tok = term2Tok;
01566                     varFirst2 = true;
01567                     secondConstant = term2Tok->strAt(2);
01568                 } else if (Token::Match(term2Tok, "%num% %any% %var%")) {
01569                     var2Tok = term2Tok->tokAt(2);
01570                     varFirst2 = false;
01571                     secondConstant = term2Tok->str();
01572                 } else {
01573                     continue;
01574                 }
01575 
01576                 if (varId != var2Tok->varId() || firstConstant.empty() || secondConstant.empty()) {
01577                     continue;
01578                 }
01579 
01580                 enum LogicError { AlwaysFalse, AlwaysTrue, FirstTrue, FirstFalse, SecondTrue, SecondFalse };
01581 
01582                 static const struct LinkedConditions {
01583                     const char *before;
01584                     Condition  c1;
01585                     const char *op2TokStr;
01586                     Condition  c2;
01587                     const char *after;
01588                     Relation   relation;
01589                     LogicError error;
01590                 } conditions[] = {
01591                     { "!!&&", { NA,    "!="   }, "%oror%", { NA,    "!="   }, "!!&&", NotEqual,  AlwaysTrue  }, // (x != 1) || (x != 3)  <- always true
01592                     { 0,      { NA,    "=="   }, "&&",     { NA,    "=="   }, 0,      NotEqual,  AlwaysFalse }, // (x == 1) && (x == 3)  <- always false
01593                     { "!!&&", { First, ">"    }, "%oror%", { First, "<"    }, "!!&&", Less,      AlwaysTrue  }, // (x > 3)  || (x < 10)  <- always true
01594                     { "!!&&", { First, ">="   }, "%oror%", { First, "<|<=" }, "!!&&", LessEqual, AlwaysTrue  }, // (x >= 3) || (x < 10)  <- always true
01595                     { "!!&&", { First, ">"    }, "%oror%", { First, "<="   }, "!!&&", LessEqual, AlwaysTrue  }, // (x > 3)  || (x <= 10) <- always true
01596                     { 0,      { First, "<"    }, "&&",     { First, ">"    }, 0,      LessEqual, AlwaysFalse }, // (x < 1)  && (x > 3)   <- always false
01597                     { 0,      { First, "<="   }, "&&",     { First, ">|>=" }, 0,      Less,      AlwaysFalse }, // (x <= 1) && (x > 3)   <- always false
01598                     { 0,      { First, "<"    }, "&&",     { First, ">="   }, 0,      Less,      AlwaysFalse }, // (x < 1)  && (x >= 3)  <- always false
01599                     { 0,      { First, ">"    }, "&&",     { NA,    "=="   }, 0,      MoreEqual, AlwaysFalse }, // (x > 5)  && (x == 1)  <- always false
01600                     { 0,      { First, "<"    }, "&&",     { NA,    "=="   }, 0,      LessEqual, AlwaysFalse }, // (x < 1)  && (x == 3)  <- always false
01601                     { 0,      { First, ">="   }, "&&",     { NA,    "=="   }, 0,      More,      AlwaysFalse }, // (x >= 5) && (x == 1)  <- always false
01602                     { 0,      { First, "<="   }, "&&",     { NA,    "=="   }, 0,      Less,      AlwaysFalse }, // (x <= 1) && (x == 3)  <- always false
01603                     { "!!&&", { NA,    "=="   }, "%oror%", { First, ">"    }, "!!&&", More,      SecondTrue  }, // (x == 4) || (x > 3)   <- second expression always true
01604                     { "!!&&", { NA,    "=="   }, "%oror%", { First, "<"    }, "!!&&", Less,      SecondTrue  }, // (x == 4) || (x < 5)   <- second expression always true
01605                     { "!!&&", { NA,    "=="   }, "%oror%", { First, ">="   }, "!!&&", MoreEqual, SecondTrue  }, // (x == 4) || (x >= 3)  <- second expression always true
01606                     { "!!&&", { NA,    "=="   }, "%oror%", { First, "<="   }, "!!&&", LessEqual, SecondTrue  }, // (x == 4) || (x <= 5)  <- second expression always true
01607                     { "!!&&", { First, ">"    }, "%oror%", { NA,    "!="   }, "!!&&", MoreEqual, SecondTrue  }, // (x > 5)  || (x != 1)  <- second expression always true
01608                     { "!!&&", { First, "<"    }, "%oror%", { NA,    "!="   }, "!!&&", LessEqual, SecondTrue  }, // (x < 1)  || (x != 3)  <- second expression always true
01609                     { "!!&&", { First, ">="   }, "%oror%", { NA,    "!="   }, "!!&&", More,      SecondTrue  }, // (x >= 5) || (x != 1)  <- second expression always true
01610                     { "!!&&", { First, "<="   }, "%oror%", { NA,    "!="   }, "!!&&", Less,      SecondTrue  }, // (x <= 1) || (x != 3)  <- second expression always true
01611                     { 0,      { First, ">"    }, "&&",     { NA,    "!="   }, 0,      MoreEqual, SecondTrue  }, // (x > 5)  && (x != 1)  <- second expression always true
01612                     { 0,      { First, "<"    }, "&&",     { NA,    "!="   }, 0,      LessEqual, SecondTrue  }, // (x < 1)  && (x != 3)  <- second expression always true
01613                     { 0,      { First, ">="   }, "&&",     { NA,    "!="   }, 0,      More,      SecondTrue  }, // (x >= 5) && (x != 1)  <- second expression always true
01614                     { 0,      { First, "<="   }, "&&",     { NA,    "!="   }, 0,      Less,      SecondTrue  }, // (x <= 1) && (x != 3)  <- second expression always true
01615                     { "!!&&", { First, ">|>=" }, "%oror%", { First, ">|>=" }, "!!&&", LessEqual, SecondTrue  }, // (x > 4)  || (x > 5)   <- second expression always true
01616                     { "!!&&", { First, "<|<=" }, "%oror%", { First, "<|<=" }, "!!&&", MoreEqual, SecondTrue  }, // (x < 5)  || (x < 4)   <- second expression always true
01617                     { 0,      { First, ">|>=" }, "&&",     { First, ">|>=" }, 0,      MoreEqual, SecondTrue  }, // (x > 4)  && (x > 5)   <- second expression always true
01618                     { 0,      { First, "<|<=" }, "&&",     { First, "<|<=" }, 0,      MoreEqual, SecondTrue  }, // (x < 5)  && (x < 4)   <- second expression always true
01619                     { 0,      { NA,    "=="   }, "&&",     { NA,    "!="   }, 0,      NotEqual,  SecondTrue  }, // (x == 3) && (x != 4)  <- second expression always true
01620                     { "!!&&", { NA,    "=="   }, "%oror%", { NA,    "!="   }, "!!&&", NotEqual,  SecondTrue  }, // (x == 3) || (x != 4)  <- second expression always true
01621                     { 0,      { NA,    "!="   }, "&&",     { NA,    "=="   }, 0,      Equal,     AlwaysFalse }, // (x != 3) && (x == 3)  <- expression always false
01622                     { "!!&&", { NA,    "!="   }, "%oror%", { NA,    "=="   }, "!!&&", Equal,     AlwaysTrue  }, // (x != 3) || (x == 3)  <- expression always true
01623                 };
01624 
01625                 for (unsigned int i = 0; i < (sizeof(conditions) / sizeof(conditions[0])); i++) {
01626                     if (!Token::Match(op2Tok, conditions[i].op2TokStr))
01627                         continue;
01628 
01629                     if (conditions[i].before != 0 && !Token::Match(tok->previous(), conditions[i].before))
01630                         continue;
01631 
01632                     if (conditions[i].after != 0 && !Token::Match(nextTok, conditions[i].after))
01633                         continue;
01634 
01635                     if (tok->previous()->isArithmeticalOp() || nextTok->isArithmeticalOp())
01636                         continue;
01637 
01638                     std::string cond1str = var1Tok->str() + " " + (varFirst1?op1Tok->str():invertOperatorForOperandSwap(op1Tok->str())) + " " + firstConstant;
01639                     std::string cond2str = var2Tok->str() + " " + (varFirst2?op3Tok->str():invertOperatorForOperandSwap(op3Tok->str())) + " " + secondConstant;
01640                     // cond1 op cond2
01641                     bool error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, false,
01642                                  varFirst1, varFirst2, firstConstant, secondConstant,
01643                                  op1Tok, op3Tok,
01644                                  conditions[i].relation);
01645                     // inv(cond1) op cond2 // invert first condition
01646                     if (!error && conditions[i].c1.position != NA)
01647                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, false,
01648                                                               !varFirst1, varFirst2, firstConstant, secondConstant,
01649                                                               op1Tok, op3Tok,
01650                                                               conditions[i].relation);
01651                     // cond1 op inv(cond2) // invert second condition
01652                     if (!error && conditions[i].c2.position != NA)
01653                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, true,
01654                                                               varFirst1, !varFirst2, firstConstant, secondConstant,
01655                                                               op1Tok, op3Tok,
01656                                                               conditions[i].relation);
01657                     // inv(cond1) op inv(cond2) // invert both conditions
01658                     if (!error && conditions[i].c1.position != NA && conditions[i].c2.position != NA)
01659                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, true,
01660                                                               !varFirst1, !varFirst2, firstConstant, secondConstant,
01661                                                               op1Tok, op3Tok,
01662                                                               conditions[i].relation);
01663                     if (!error)
01664                         std::swap(cond1str, cond2str);
01665                     // cond2 op cond1 // swap conditions
01666                     if (!error)
01667                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, false,
01668                                                               varFirst2, varFirst1, secondConstant, firstConstant,
01669                                                               op3Tok, op1Tok,
01670                                                               conditions[i].relation);
01671                     // cond2 op inv(cond1) // swap conditions; invert first condition
01672                     if (!error && conditions[i].c1.position != NA)
01673                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, false,
01674                                                               !varFirst2, varFirst1, secondConstant, firstConstant,
01675                                                               op3Tok, op1Tok,
01676                                                               conditions[i].relation);
01677                     // inv(cond2) op cond1 // swap conditions; invert second condition
01678                     if (!error && conditions[i].c2.position != NA)
01679                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, false, true,
01680                                                               varFirst2, !varFirst1, secondConstant, firstConstant,
01681                                                               op3Tok, op1Tok,
01682                                                               conditions[i].relation);
01683                     // inv(cond2) op inv(cond1) // swap conditions; invert both conditions
01684                     if (!error && conditions[i].c1.position != NA && conditions[i].c2.position != NA)
01685                         error = analyzeLogicOperatorCondition(conditions[i].c1, conditions[i].c2, true, true,
01686                                                               !varFirst2, !varFirst1, secondConstant, firstConstant,
01687                                                               op3Tok, op1Tok,
01688                                                               conditions[i].relation);
01689 
01690                     if (error) {
01691                         if (conditions[i].error == AlwaysFalse || conditions[i].error == AlwaysTrue) {
01692                             if (warning) {
01693                                 const std::string text = cond1str + " " + op2Tok->str() + " " + cond2str;
01694                                 incorrectLogicOperatorError(term1Tok, text, conditions[i].error == AlwaysTrue);
01695                             }
01696                         } else {
01697                             if (style) {
01698                                 const std::string text = "If " + cond1str + ", the comparison " + cond2str +
01699                                                          " is always " + ((conditions[i].error == SecondTrue || conditions[i].error == AlwaysTrue) ? "true" : "false") + ".";
01700                                 redundantConditionError(term1Tok, text);
01701                             }
01702                         }
01703                         break;
01704                     }
01705                 }
01706             }
01707         }
01708     }
01709 }
01710 
01711 void CheckOther::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always)
01712 {
01713     if (always)
01714         reportError(tok, Severity::warning, "incorrectLogicOperator",
01715                     "Logical disjunction always evaluates to true: " + condition + ".\n"
01716                     "Logical disjunction always evaluates to true: " + condition + ". "
01717                     "Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?");
01718     else
01719         reportError(tok, Severity::warning, "incorrectLogicOperator",
01720                     "Logical conjunction always evaluates to false: " + condition + ".\n"
01721                     "Logical conjunction always evaluates to false: " + condition + ". "
01722                     "Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?");
01723 }
01724 
01725 void CheckOther::redundantConditionError(const Token *tok, const std::string &text)
01726 {
01727     reportError(tok, Severity::style, "redundantCondition", "Redundant condition: " + text);
01728 }
01729 
01730 //---------------------------------------------------------------------------
01731 // strtol(str, 0, radix)  <- radix must be 0 or 2-36
01732 //---------------------------------------------------------------------------
01733 void CheckOther::invalidFunctionUsage()
01734 {
01735     // strtol and strtoul..
01736     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
01737         if (!Token::Match(tok, "strtol|strtoul|strtoll|strtoull|wcstol|wcstoul|wcstoll|wcstoull ("))
01738             continue;
01739 
01740         const std::string& funcname = tok->str();
01741         tok = tok->tokAt(2);
01742         // Locate the third parameter of the function call..
01743         for (int i = 0; i < 2 && tok; i++)
01744             tok = tok->nextArgument();
01745 
01746         if (Token::Match(tok, "%num% )")) {
01747             const MathLib::bigint radix = MathLib::toLongNumber(tok->str());
01748             if (!(radix == 0 || (radix >= 2 && radix <= 36))) {
01749                 dangerousUsageStrtolError(tok, funcname);
01750             }
01751         } else
01752             break;
01753     }
01754 
01755     // sprintf|snprintf overlapping data
01756     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
01757         // Get variable id of target buffer..
01758         unsigned int varid = 0;
01759 
01760         if (Token::Match(tok, "sprintf|snprintf|swprintf ( %var% ,"))
01761             varid = tok->tokAt(2)->varId();
01762 
01763         else if (Token::Match(tok, "sprintf|snprintf|swprintf ( %var% . %var% ,"))
01764             varid = tok->tokAt(4)->varId();
01765 
01766         if (varid == 0)
01767             continue;
01768 
01769         // goto ","
01770         const Token *tok2 = tok->tokAt(3);
01771         while (tok2->str() != ",")
01772             tok2 = tok2->next();
01773 
01774         tok2 = tok2->next(); // Jump behind ","
01775 
01776         if (tok->str() == "snprintf" || tok->str() == "swprintf") { // Jump over second parameter for snprintf and swprintf
01777             tok2 = tok2->nextArgument();
01778             if (!tok2)
01779                 continue;
01780         }
01781 
01782         // is any source buffer overlapping the target buffer?
01783         do {
01784             if (Token::Match(tok2, "%varid% [,)]", varid)) {
01785                 sprintfOverlappingDataError(tok2, tok2->str());
01786                 break;
01787             }
01788         } while (NULL != (tok2 = tok2->nextArgument()));
01789     }
01790 }
01791 
01792 void CheckOther::dangerousUsageStrtolError(const Token *tok, const std::string& funcname)
01793 {
01794     reportError(tok, Severity::error, "dangerousUsageStrtol", "Invalid radix in call to " + funcname + "(). It must be 0 or 2-36.");
01795 }
01796 
01797 void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string &varname)
01798 {
01799     reportError(tok, Severity::error, "sprintfOverlappingData",
01800                 "Undefined behavior: Variable '" + varname + "' is used as parameter and destination in s[n]printf().\n"
01801                 "The variable '" + varname + "' is used both as a parameter and as destination in "
01802                 "s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) "
01803                 "documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
01804                 "\"If copying takes place between objects that overlap as a result of a call "
01805                 "to sprintf() or snprintf(), the results are undefined.\"");
01806 }
01807 
01808 //---------------------------------------------------------------------------
01809 //    if (!x==3) <- Probably meant to be "x!=3"
01810 //---------------------------------------------------------------------------
01811 
01812 static bool isBool(const Variable* var)
01813 {
01814     return(var && var->typeEndToken()->str() == "bool");
01815 }
01816 static bool isNonBoolStdType(const Variable* var)
01817 {
01818     return(var && var->typeEndToken()->isStandardType() && var->typeEndToken()->str() != "bool");
01819 }
01820 void CheckOther::checkComparisonOfBoolWithInt()
01821 {
01822     if (!_settings->isEnabled("warning"))
01823         return;
01824 
01825     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
01826     const std::size_t functions = symbolDatabase->functionScopes.size();
01827     for (std::size_t i = 0; i < functions; ++i) {
01828         const Scope * scope = symbolDatabase->functionScopes[i];
01829         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
01830             if (tok->next() && tok->next()->type() == Token::eComparisonOp && (!tok->previous() || !tok->previous()->isArithmeticalOp()) && (!tok->tokAt(3) || !tok->tokAt(3)->isArithmeticalOp())) {
01831                 const Token* const right = tok->tokAt(2);
01832                 if ((tok->varId() && right->isNumber()) || (tok->isNumber() && right->varId())) { // Comparing variable with number
01833                     const Token* varTok = tok;
01834                     const Token* numTok = right;
01835                     if (tok->isNumber() && right->varId()) // num with var
01836                         std::swap(varTok, numTok);
01837                     if (isBool(varTok->variable()) && // Variable has to be a boolean
01838                         ((tok->strAt(1) != "==" && tok->strAt(1) != "!=") ||
01839                          (MathLib::toLongNumber(numTok->str()) != 0 && MathLib::toLongNumber(numTok->str()) != 1))) { // == 0 and != 0 are allowed, for C also == 1 and != 1
01840                         comparisonOfBoolWithIntError(varTok, numTok->str(), tok->strAt(1) == "==" || tok->strAt(1) == "!=");
01841                     }
01842                 } else if (tok->isBoolean() && right->varId()) { // Comparing boolean constant with variable
01843                     if (isNonBoolStdType(right->variable())) { // Variable has to be of non-boolean standard type
01844                         comparisonOfBoolWithIntError(right, tok->str(), false);
01845                     } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") {
01846                         comparisonOfBoolWithInvalidComparator(right, tok->str());
01847                     }
01848                 } else if (tok->varId() && right->isBoolean()) { // Comparing variable with boolean constant
01849                     if (isNonBoolStdType(tok->variable())) { // Variable has to be of non-boolean standard type
01850                         comparisonOfBoolWithIntError(tok, right->str(), false);
01851                     } else if (tok->strAt(1) != "==" && tok->strAt(1) != "!=") {
01852                         comparisonOfBoolWithInvalidComparator(right, tok->str());
01853                     }
01854                 } else if (tok->isNumber() && right->isBoolean()) { // number constant with boolean constant
01855                     comparisonOfBoolWithIntError(tok, right->str(), false);
01856                 } else if (tok->isBoolean() && right->isNumber()) { // number constant with boolean constant
01857                     comparisonOfBoolWithIntError(tok, tok->str(), false);
01858                 } else if (tok->varId() && right->varId()) { // Comparing two variables, one of them boolean, one of them integer
01859                     const Variable* var1 = right->variable();
01860                     const Variable* var2 = tok->variable();
01861                     if (isBool(var1) && isNonBoolStdType(var2)) // Comparing boolean with non-bool standard type
01862                         comparisonOfBoolWithIntError(tok, var1->name(), false);
01863                     else if (isNonBoolStdType(var1) && isBool(var2)) // Comparing non-bool standard type with boolean
01864                         comparisonOfBoolWithIntError(tok, var2->name(), false);
01865                 }
01866             }
01867         }
01868     }
01869 }
01870 
01871 void CheckOther::comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1)
01872 {
01873     if (n0o1)
01874         reportError(tok, Severity::warning, "comparisonOfBoolWithInt",
01875                     "Comparison of a boolean with an integer that is neither 1 nor 0.\n"
01876                     "The expression '" + expression + "' is of type 'bool' "
01877                     "and it is compared against an integer value that is "
01878                     "neither 1 nor 0.");
01879     else
01880         reportError(tok, Severity::warning, "comparisonOfBoolWithInt",
01881                     "Comparison of a boolean with an integer.\n"
01882                     "The expression '" + expression + "' is of type 'bool' "
01883                     "and it is compared against an integer value.");
01884 }
01885 
01886 void CheckOther::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression)
01887 {
01888     reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator",
01889                 "Comparison of a boolean value using relational operator (<, >, <= or >=).\n"
01890                 "The result of the expression '" + expression + "' is of type 'bool'. "
01891                 "Comparing 'bool' value using relational (<, >, <= or >=)"
01892                 " operator could cause unexpected results.");
01893 }
01894 
01895 //---------------------------------------------------------------------------
01896 //    Find consecutive return, break, continue, goto or throw statements. e.g.:
01897 //        break; break;
01898 //    Detect dead code, that follows such a statement. e.g.:
01899 //        return(0); foo();
01900 //---------------------------------------------------------------------------
01901 void CheckOther::checkUnreachableCode()
01902 {
01903     if (!_settings->isEnabled("style"))
01904         return;
01905 
01906     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
01907         const Token* secondBreak = 0;
01908         const Token* labelName = 0;
01909         if (tok->str() == "(")
01910             tok = tok->link();
01911         else if (Token::Match(tok, "break|continue ;"))
01912             secondBreak = tok->tokAt(2);
01913         else if (Token::Match(tok, "[;{}:] return|throw")) {
01914             tok = tok->next(); // tok should point to return or throw
01915             for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
01916                 if (tok2->str() == ";") {
01917                     secondBreak = tok2->next();
01918                     break;
01919                 }
01920         } else if (Token::Match(tok, "goto %any% ;")) {
01921             secondBreak = tok->tokAt(3);
01922             labelName = tok->next();
01923         }
01924 
01925         // Statements follow directly, no line between them. (#3383)
01926         // TODO: Try to find a better way to avoid false positives due to preprocessor configurations.
01927         bool inconclusive = secondBreak && (secondBreak->linenr()-1 > secondBreak->previous()->linenr());
01928 
01929         if (secondBreak && (_settings->inconclusive || !inconclusive)) {
01930             if (Token::Match(secondBreak, "continue|goto|throw") ||
01931                 (secondBreak->str() == "return" && (tok->str() == "return" || secondBreak->strAt(1) == ";"))) { // return with value after statements like throw can be necessary to make a function compile
01932                 duplicateBreakError(secondBreak, inconclusive);
01933                 tok = Token::findmatch(secondBreak, "[}:]");
01934             } else if (secondBreak->str() == "break") { // break inside switch as second break statement should not issue a warning
01935                 if (tok->str() == "break") // If the previous was a break, too: Issue warning
01936                     duplicateBreakError(secondBreak, inconclusive);
01937                 else {
01938                     if (tok->scope()->type != Scope::eSwitch) // Check, if the enclosing scope is a switch
01939                         duplicateBreakError(secondBreak, inconclusive);
01940                 }
01941                 tok = Token::findmatch(secondBreak, "[}:]");
01942             } else if (!Token::Match(secondBreak, "return|}|case|default") && secondBreak->strAt(1) != ":") { // TODO: No bailout for unconditional scopes
01943                 // If the goto label is followed by a loop construct in which the label is defined it's quite likely
01944                 // that the goto jump was intended to skip some code on the first loop iteration.
01945                 bool labelInFollowingLoop = false;
01946                 if (labelName && Token::Match(secondBreak, "while|do|for")) {
01947                     const Token *scope = Token::findsimplematch(secondBreak, "{");
01948                     if (scope) {
01949                         for (const Token *tokIter = scope; tokIter != scope->link() && tokIter; tokIter = tokIter->next()) {
01950                             if (Token::Match(tokIter, "[;{}] %any% :") && labelName->str() == tokIter->strAt(1)) {
01951                                 labelInFollowingLoop = true;
01952                                 break;
01953                             }
01954                         }
01955                     }
01956                 }
01957                 if (!labelInFollowingLoop)
01958                     unreachableCodeError(secondBreak, inconclusive);
01959                 tok = Token::findmatch(secondBreak, "[}:]");
01960             } else
01961                 tok = secondBreak;
01962 
01963             if (!tok)
01964                 break;
01965         }
01966     }
01967 }
01968 
01969 void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
01970 {
01971     reportError(tok, Severity::style, "duplicateBreak",
01972                 "Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
01973                 "Consecutive return, break, continue, goto or throw statements are unnecessary. "
01974                 "The second statement can never be executed, and so should be removed.", inconclusive);
01975 }
01976 
01977 void CheckOther::unreachableCodeError(const Token *tok, bool inconclusive)
01978 {
01979     reportError(tok, Severity::style, "unreachableCode",
01980                 "Statements following return, break, continue, goto or throw will never be executed.", inconclusive);
01981 }
01982 
01983 //---------------------------------------------------------------------------
01984 // Check for unsigned divisions
01985 //---------------------------------------------------------------------------
01986 bool CheckOther::isUnsigned(const Variable* var) const
01987 {
01988     return(var && var->typeStartToken()->isUnsigned() && !var->isPointer() && !var->isArray() && _tokenizer->sizeOfType(var->typeStartToken()) >= _settings->sizeof_int);
01989 }
01990 bool CheckOther::isSigned(const Variable* var)
01991 {
01992     return(var && !var->typeStartToken()->isUnsigned() && Token::Match(var->typeEndToken(), "int|char|short|long") && !var->isPointer() && !var->isArray());
01993 }
01994 
01995 void CheckOther::checkUnsignedDivision()
01996 {
01997     bool warning = _settings->isEnabled("warning");
01998 
01999     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
02000     const std::size_t functions = symbolDatabase->functionScopes.size();
02001     for (std::size_t i = 0; i < functions; ++i) {
02002         const Scope * scope = symbolDatabase->functionScopes[i];
02003         const Token* ifTok = 0;
02004         // Check for "ivar / uvar" and "uvar / ivar"
02005         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02006 
02007             if (Token::Match(tok, "[).]")) // Don't check members or casted variables
02008                 continue;
02009 
02010             if (Token::Match(tok->next(), "%var% / %num%")) {
02011                 if (tok->strAt(3)[0] == '-' && isUnsigned(tok->next()->variable())) {
02012                     udivError(tok->next(), false);
02013                 }
02014             } else if (Token::Match(tok->next(), "%num% / %var%")) {
02015                 if (tok->strAt(1)[0] == '-' && isUnsigned(tok->tokAt(3)->variable())) {
02016                     udivError(tok->next(), false);
02017                 }
02018             } else if (Token::Match(tok->next(), "%var% / %var%") && _settings->inconclusive && warning && !ifTok) {
02019                 const Variable* var1 = tok->next()->variable();
02020                 const Variable* var2 = tok->tokAt(3)->variable();
02021                 if ((isUnsigned(var1) && isSigned(var2)) || (isUnsigned(var2) && isSigned(var1))) {
02022                     udivError(tok->next(), true);
02023                 }
02024             } else if (!ifTok && Token::simpleMatch(tok, "if ("))
02025                 ifTok = tok->next()->link()->next()->link();
02026             else if (ifTok == tok)
02027                 ifTok = 0;
02028         }
02029     }
02030 }
02031 
02032 void CheckOther::udivError(const Token *tok, bool inconclusive)
02033 {
02034     if (inconclusive)
02035         reportError(tok, Severity::warning, "udivError", "Division with signed and unsigned operators. The result might be wrong.", true);
02036     else
02037         reportError(tok, Severity::error, "udivError", "Unsigned division. The result will be wrong.");
02038 }
02039 
02040 //---------------------------------------------------------------------------
02041 // memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
02042 //---------------------------------------------------------------------------
02043 void CheckOther::checkMemsetZeroBytes()
02044 {
02045     if (!_settings->isEnabled("warning"))
02046         return;
02047 
02048     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02049     const std::size_t functions = symbolDatabase->functionScopes.size();
02050     for (std::size_t i = 0; i < functions; ++i) {
02051         const Scope * scope = symbolDatabase->functionScopes[i];
02052         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02053             if (Token::simpleMatch(tok, "memset (")) {
02054                 const Token* lastParamTok = tok->next()->link()->previous();
02055                 if (lastParamTok->str() == "0")
02056                     memsetZeroBytesError(tok, tok->strAt(2));
02057             }
02058         }
02059     }
02060 }
02061 
02062 void CheckOther::memsetZeroBytesError(const Token *tok, const std::string &varname)
02063 {
02064     const std::string summary("memset() called to fill 0 bytes of '" + varname + "'.");
02065     const std::string verbose(summary + " Second and third arguments might be inverted.");
02066     reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose);
02067 }
02068 
02069 //---------------------------------------------------------------------------
02070 // Check scope of variables..
02071 //---------------------------------------------------------------------------
02072 void CheckOther::checkVariableScope()
02073 {
02074     if (!_settings->isEnabled("style"))
02075         return;
02076 
02077     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02078 
02079     for (unsigned int i = 1; i < symbolDatabase->getVariableListSize(); i++) {
02080         const Variable* var = symbolDatabase->getVariableFromVarId(i);
02081         if (!var || !var->isLocal() || (!var->isPointer() && !var->typeStartToken()->isStandardType() && !var->typeStartToken()->next()->isStandardType()))
02082             continue;
02083 
02084         bool forHead = false; // Don't check variables declared in header of a for loop
02085         for (const Token* tok = var->typeStartToken(); tok; tok = tok->previous()) {
02086             if (tok->str() == "(") {
02087                 forHead = true;
02088                 break;
02089             } else if (tok->str() == "{" || tok->str() == ";" || tok->str() == "}")
02090                 break;
02091         }
02092         if (forHead)
02093             continue;
02094 
02095         const Token* tok = var->nameToken()->next();
02096         if (Token::Match(tok, "; %varid% = %any% ;", var->varId())) {
02097             tok = tok->tokAt(3);
02098             if (!tok->isNumber() && tok->type() != Token::eString && tok->type() != Token::eChar && !tok->isBoolean())
02099                 continue;
02100         } else if ((tok->str() == "=" || tok->str() == "(") &&
02101                    ((!tok->next()->isNumber() && tok->next()->type() != Token::eString && tok->next()->type() != Token::eChar && !tok->next()->isBoolean()) || tok->strAt(2) != ";"))
02102             continue;
02103 
02104         bool reduce = true;
02105         bool used = false; // Don't warn about unused variables
02106         for (; tok != var->scope()->classEnd; tok = tok->next()) {
02107             if (tok->str() == "{" && tok->strAt(-1) != "=") {
02108                 if (used) {
02109                     bool used2 = false;
02110                     if (!checkInnerScope(tok, var, used2) || used2) {
02111                         reduce = false;
02112                         break;
02113                     }
02114                 } else if (!checkInnerScope(tok, var, used)) {
02115                     reduce = false;
02116                     break;
02117                 }
02118 
02119                 tok = tok->link();
02120             } else if (tok->varId() == var->varId() || tok->str() == "goto") {
02121                 reduce = false;
02122                 break;
02123             }
02124         }
02125 
02126         if (reduce && used)
02127             variableScopeError(var->nameToken(), var->name());
02128     }
02129 }
02130 
02131 bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used)
02132 {
02133     const Scope* scope = tok->next()->scope();
02134     bool loopVariable = scope->type == Scope::eFor || scope->type == Scope::eWhile || scope->type == Scope::eDo;
02135     bool noContinue = true;
02136     const Token* forHeadEnd = 0;
02137     const Token* end = tok->link();
02138     if (scope->type == Scope::eUnconditional && (tok->strAt(-1) == ")" || tok->previous()->isName())) // Might be an unknown macro like BOOST_FOREACH
02139         loopVariable = true;
02140 
02141     if (scope->type == Scope::eDo) {
02142         end = end->linkAt(2);
02143     } else if (loopVariable && tok->strAt(-1) == ")") {
02144         tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
02145     } else if (scope->type == Scope::eSwitch) {
02146         for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
02147             if (used) {
02148                 bool used2 = false;
02149                 if (!checkInnerScope((*i)->classStart, var, used2) || used2) {
02150                     return false;
02151                 }
02152             } else if (!checkInnerScope((*i)->classStart, var, used)) {
02153                 return false;
02154             }
02155         }
02156     }
02157 
02158     for (; tok != end; tok = tok->next()) {
02159         if (tok->str() == "goto")
02160             return false;
02161         if (tok->str() == "continue")
02162             noContinue = false;
02163 
02164         if (Token::simpleMatch(tok, "for ("))
02165             forHeadEnd = tok->linkAt(1);
02166         if (tok == forHeadEnd)
02167             forHeadEnd = 0;
02168 
02169         if (loopVariable && noContinue && tok->scope() == scope && !forHeadEnd && scope->type != Scope::eSwitch && Token::Match(tok, "%varid% =", var->varId())) { // Assigned in outer scope.
02170             loopVariable = false;
02171             unsigned int indent = 0;
02172             for (const Token* tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) { // Ensure that variable isn't used on right side of =, too
02173                 if (tok2->str() == "(")
02174                     indent++;
02175                 else if (tok2->str() == ")") {
02176                     if (indent == 0)
02177                         break;
02178                     indent--;
02179                 } else if (tok2->str() == ";")
02180                     break;
02181                 else if (tok2->varId() == var->varId()) {
02182                     loopVariable = true;
02183                     break;
02184                 }
02185             }
02186         }
02187 
02188         if (loopVariable && Token::Match(tok, "%varid% !!=", var->varId())) // Variable used in loop
02189             return false;
02190 
02191         if (Token::Match(tok, "& %varid%", var->varId())) // Taking address of variable
02192             return false;
02193 
02194         if (Token::Match(tok, "= %varid%", var->varId()) && (var->isArray() || var->isPointer())) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
02195             return false;
02196 
02197         if (tok->varId() == var->varId()) {
02198             used = true;
02199             if (scope->type == Scope::eSwitch && scope == tok->scope())
02200                 return false; // Used in outer switch scope - unsafe or impossible to reduce scope
02201         }
02202     }
02203 
02204     return true;
02205 }
02206 
02207 void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
02208 {
02209     reportError(tok,
02210                 Severity::style,
02211                 "variableScope",
02212                 "The scope of the variable '" + varname + "' can be reduced.\n"
02213                 "The scope of the variable '" + varname + "' can be reduced. Warning: Be careful "
02214                 "when fixing this message, especially when there are inner loops. Here is an "
02215                 "example where cppcheck will write that the scope for 'i' can be reduced:\n"
02216                 "void f(int x)\n"
02217                 "{\n"
02218                 "    int i = 0;\n"
02219                 "    if (x) {\n"
02220                 "        // it's safe to move 'int i = 0;' here\n"
02221                 "        for (int n = 0; n < 10; ++n) {\n"
02222                 "            // it is possible but not safe to move 'int i = 0;' here\n"
02223                 "            do_something(&i);\n"
02224                 "        }\n"
02225                 "    }\n"
02226                 "}\n"
02227                 "When you see this message it is always safe to reduce the variable scope 1 level.");
02228 }
02229 
02230 //---------------------------------------------------------------------------
02231 // Check for constant function parameters
02232 //---------------------------------------------------------------------------
02233 void CheckOther::checkConstantFunctionParameter()
02234 {
02235     if (!_settings->isEnabled("performance") || _tokenizer->isC())
02236         return;
02237 
02238     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
02239 
02240     for (unsigned int i = 1; i < symbolDatabase->getVariableListSize(); i++) {
02241         const Variable* var = symbolDatabase->getVariableFromVarId(i);
02242         if (!var || !var->isArgument() || !var->isClass() || !var->isConst() || var->isPointer() || var->isArray() || var->isReference())
02243             continue;
02244 
02245         const Token* const tok = var->typeStartToken();
02246         // TODO: False negatives. This pattern only checks for string.
02247         //       Investigate if there are other classes in the std
02248         //       namespace and add them to the pattern. There are
02249         //       streams for example (however it seems strange with
02250         //       const stream parameter).
02251         if (Token::Match(tok, "std :: string|wstring")) {
02252             passedByValueError(tok, var->name());
02253         } else if (Token::Match(tok, "std :: %type% <") && !Token::simpleMatch(tok->linkAt(3), "> ::")) {
02254             passedByValueError(tok, var->name());
02255         } else if (var->type()) {  // Check if type is a struct or class.
02256             passedByValueError(tok, var->name());
02257         }
02258     }
02259 }
02260 
02261 void CheckOther::passedByValueError(const Token *tok, const std::string &parname)
02262 {
02263     reportError(tok, Severity::performance, "passedByValue",
02264                 "Function parameter '" + parname + "' should be passed by reference.\n"
02265                 "Parameter '" +  parname + "' is passed by value. It could be passed "
02266                 "as a (const) reference which is usually faster and recommended in C++.");
02267 }
02268 
02269 //---------------------------------------------------------------------------
02270 // Check usage of char variables..
02271 //---------------------------------------------------------------------------
02272 static bool isChar(const Variable* var)
02273 {
02274     return(var && !var->isPointer() && !var->isArray() && var->typeStartToken()->str() == "char");
02275 }
02276 
02277 static bool isSignedChar(const Variable* var)
02278 {
02279     return(isChar(var) && !var->typeStartToken()->isUnsigned());
02280 }
02281 
02282 void CheckOther::checkCharVariable()
02283 {
02284     if (!_settings->isEnabled("warning"))
02285         return;
02286 
02287     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02288     const std::size_t functions = symbolDatabase->functionScopes.size();
02289     for (std::size_t i = 0; i < functions; ++i) {
02290         const Scope * scope = symbolDatabase->functionScopes[i];
02291         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
02292             if ((tok->str() != ".") && Token::Match(tok->next(), "%var% [ %var% ]")) {
02293                 const Variable* arrayvar = tok->next()->variable();
02294                 const Variable* indexvar = tok->tokAt(3)->variable();
02295                 const MathLib::bigint arraysize = (arrayvar && arrayvar->isArray()) ? arrayvar->dimension(0U) : 0;
02296                 if (isSignedChar(indexvar) && arraysize > 0x80)
02297                     charArrayIndexError(tok->next());
02298             }
02299 
02300             else if (Token::Match(tok, "[;{}] %var% = %any% [&^|] %any% ;")) {
02301                 // is a char variable used in the calculation?
02302                 if (!isSignedChar(tok->tokAt(3)->variable()) &&
02303                     !isSignedChar(tok->tokAt(5)->variable()))
02304                     continue;
02305 
02306                 // it's ok with a bitwise and where the other operand is 0xff or less..
02307                 if (tok->strAt(4) == "&") {
02308                     if (tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
02309                         continue;
02310                     if (tok->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok->strAt(5)))
02311                         continue;
02312                 }
02313 
02314                 // is the result stored in a short|int|long?
02315                 const Variable *var = tok->next()->variable();
02316                 if (var && Token::Match(var->typeStartToken(), "short|int|long") && !var->isPointer() && !var->isArray())
02317                     charBitOpError(tok->tokAt(4)); // This is an error..
02318             }
02319 
02320             else if (Token::Match(tok, "[;{}] %var% = %any% [&^|] ( * %var% ) ;")) {
02321                 const Variable* var = tok->tokAt(7)->variable();
02322                 if (!var || !var->isPointer() || var->typeStartToken()->str() != "char" || var->typeStartToken()->isUnsigned())
02323                     continue;
02324                 // it's ok with a bitwise and where the other operand is 0xff or less..
02325                 if (tok->strAt(4) == "&" && tok->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok->strAt(3)))
02326                     continue;
02327 
02328                 // is the result stored in a short|int|long?
02329                 var = tok->next()->variable();
02330                 if (var && Token::Match(var->typeStartToken(), "short|int|long") && !var->isPointer() && !var->isArray())
02331                     charBitOpError(tok->tokAt(4)); // This is an error..
02332             }
02333         }
02334     }
02335 }
02336 
02337 void CheckOther::charArrayIndexError(const Token *tok)
02338 {
02339     reportError(tok,
02340                 Severity::warning,
02341                 "charArrayIndex",
02342                 "Signed 'char' type used as array index.\n"
02343                 "Signed 'char' type used as array index. If the value "
02344                 "can be greater than 127 there will be a buffer underflow "
02345                 "because of sign extension.");
02346 }
02347 
02348 void CheckOther::charBitOpError(const Token *tok)
02349 {
02350     reportError(tok,
02351                 Severity::warning,
02352                 "charBitOp",
02353                 "When using 'char' variables in bit operations, sign extension can generate unexpected results.\n"
02354                 "When using 'char' variables in bit operations, sign extension can generate unexpected results. For example:\n"
02355                 "    char c = 0x80;\n"
02356                 "    int i = 0 | c;\n"
02357                 "    if (i & 0x8000)\n"
02358                 "        printf(\"not expected\");\n"
02359                 "The \"not expected\" will be printed on the screen.");
02360 }
02361 
02362 //---------------------------------------------------------------------------
02363 // Incomplete statement..
02364 //---------------------------------------------------------------------------
02365 void CheckOther::checkIncompleteStatement()
02366 {
02367     if (!_settings->isEnabled("warning"))
02368         return;
02369 
02370     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
02371         if (tok->str() == "(") {
02372             tok = tok->link();
02373             if (Token::simpleMatch(tok, ") {") && Token::simpleMatch(tok->next()->link(), "} ;"))
02374                 tok = tok->next()->link();
02375         }
02376 
02377         else if (Token::simpleMatch(tok, "= {"))
02378             tok = tok->next()->link();
02379 
02380         // C++11 struct/array initialization in initializer list
02381         else if (tok->str() == "{" && Token::Match(tok->tokAt(-2), ",|: %var%") && Token::Match(tok->link(), "} [,{]"))
02382             tok = tok->link();
02383 
02384         // C++11 vector initialization
02385         else if (Token::Match(tok,"> %var% {"))
02386             tok = tok->linkAt(2);
02387 
02388         else if (Token::Match(tok, "[;{}] %str%") || Token::Match(tok, "[;{}] %num%")) {
02389             // No warning if numeric constant is followed by a "." or ","
02390             if (Token::Match(tok->next(), "%num% [,.]"))
02391                 continue;
02392 
02393             // bailout if there is a "? :" in this statement
02394             bool bailout = false;
02395             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
02396                 if (tok2->str() == "?")
02397                     bailout = true;
02398                 else if (tok2->str() == ";")
02399                     break;
02400             }
02401             if (bailout)
02402                 continue;
02403 
02404             constStatementError(tok->next(), tok->next()->isNumber() ? "numeric" : "string");
02405         }
02406     }
02407 }
02408 
02409 void CheckOther::constStatementError(const Token *tok, const std::string &type)
02410 {
02411     reportError(tok, Severity::warning, "constStatement", "Redundant code: Found a statement that begins with " + type + " constant.");
02412 }
02413 
02414 //---------------------------------------------------------------------------
02415 // str plus char
02416 //---------------------------------------------------------------------------
02417 
02418 void CheckOther::strPlusChar()
02419 {
02420     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
02421     const std::size_t functions = symbolDatabase->functionScopes.size();
02422     for (std::size_t i = 0; i < functions; ++i) {
02423         const Scope * scope = symbolDatabase->functionScopes[i];
02424         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02425             if (Token::Match(tok, "[=(] %str% + %any%")) {
02426                 // char constant..
02427                 if (tok->tokAt(3)->type() == Token::eChar)
02428                     strPlusCharError(tok->next());
02429 
02430                 // char variable..
02431                 if (isChar(tok->tokAt(3)->variable()))
02432                     strPlusCharError(tok->next());
02433             }
02434         }
02435     }
02436 }
02437 
02438 void CheckOther::strPlusCharError(const Token *tok)
02439 {
02440     reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic. A value of type 'char' is added to a string literal.");
02441 }
02442 
02443 //---------------------------------------------------------------------------
02444 //---------------------------------------------------------------------------
02445 void CheckOther::checkZeroDivision()
02446 {
02447     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
02448         if (Token::Match(tok, "[/%] %num%") &&
02449             MathLib::isInt(tok->next()->str()) &&
02450             MathLib::toLongNumber(tok->next()->str()) == 0L) {
02451             zerodivError(tok);
02452         } else if (Token::Match(tok, "div|ldiv|lldiv|imaxdiv ( %num% , %num% )") &&
02453                    MathLib::isInt(tok->strAt(4)) &&
02454                    MathLib::toLongNumber(tok->strAt(4)) == 0L) {
02455             zerodivError(tok);
02456         }
02457     }
02458 }
02459 
02460 void CheckOther::zerodivError(const Token *tok)
02461 {
02462     reportError(tok, Severity::error, "zerodiv", "Division by zero.");
02463 }
02464 
02465 //---------------------------------------------------------------------------
02466 //---------------------------------------------------------------------------
02467 void CheckOther::checkMathFunctions()
02468 {
02469     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02470     const std::size_t functions = symbolDatabase->functionScopes.size();
02471     for (std::size_t i = 0; i < functions; ++i) {
02472         const Scope * scope = symbolDatabase->functionScopes[i];
02473         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02474             if (tok->varId())
02475                 continue;
02476             if (Token::Match(tok, "log|log10 ( %num% )")) {
02477                 bool isNegative = MathLib::isNegative(tok->strAt(2));
02478                 bool isInt = MathLib::isInt(tok->strAt(2));
02479                 bool isFloat = MathLib::isFloat(tok->strAt(2));
02480                 if (isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) {
02481                     mathfunctionCallError(tok); // case log(-2)
02482                 } else if (isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) {
02483                     mathfunctionCallError(tok); // case log(-2.0)
02484                 } else if (!isNegative && isFloat && MathLib::toDoubleNumber(tok->strAt(2)) <= 0.) {
02485                     mathfunctionCallError(tok); // case log(0.0)
02486                 } else if (!isNegative && isInt && MathLib::toLongNumber(tok->strAt(2)) <= 0) {
02487                     mathfunctionCallError(tok); // case log(0)
02488                 }
02489             }
02490 
02491             // acos( x ), asin( x )  where x is defined for interval [-1,+1], but not beyond
02492             else if (Token::Match(tok, "acos|asin ( %num% )") &&
02493                      std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) {
02494                 mathfunctionCallError(tok);
02495             }
02496             // sqrt( x ): if x is negative the result is undefined
02497             else if (Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") &&
02498                      MathLib::isNegative(tok->strAt(2))) {
02499                 mathfunctionCallError(tok);
02500             }
02501             // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
02502             else if (Token::Match(tok, "atan2 ( %num% , %num% )") &&
02503                      MathLib::isNullValue(tok->strAt(2)) &&
02504                      MathLib::isNullValue(tok->strAt(4))) {
02505                 mathfunctionCallError(tok, 2);
02506             }
02507             // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
02508             else if (Token::Match(tok, "fmod ( %any%")) {
02509                 const Token* nextArg = tok->tokAt(2)->nextArgument();
02510                 if (nextArg && nextArg->isNumber() && MathLib::isNullValue(nextArg->str()))
02511                     mathfunctionCallError(tok, 2);
02512             }
02513             // pow ( x , y) If x is zero, and y is negative --> division by zero
02514             else if (Token::Match(tok, "pow ( %num% , %num% )") &&
02515                      MathLib::isNullValue(tok->strAt(2))  &&
02516                      MathLib::isNegative(tok->strAt(4))) {
02517                 mathfunctionCallError(tok, 2);
02518             }
02519         }
02520     }
02521 }
02522 
02523 void CheckOther::mathfunctionCallError(const Token *tok, const unsigned int numParam)
02524 {
02525     if (tok) {
02526         if (numParam == 1)
02527             reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->strAt(2) + " to " + tok->str() + "() leads to undefined result.");
02528         else if (numParam == 2)
02529             reportError(tok, Severity::error, "wrongmathcall", "Passing values " + tok->strAt(2) + " and " + tok->strAt(4) + " to " + tok->str() + "() leads to undefined result.");
02530     } else
02531         reportError(tok, Severity::error, "wrongmathcall", "Passing value '#' to #() leads to undefined result.");
02532 }
02533 
02534 //---------------------------------------------------------------------------
02535 //---------------------------------------------------------------------------
02536 void CheckOther::checkCCTypeFunctions()
02537 {
02538     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
02539         if (tok->varId() == 0 &&
02540             Token::Match(tok, "isalnum|isalpha|iscntrl|isdigit|isgraph|islower|isprint|ispunct|isspace|isupper|isxdigit ( %num% ,|)") &&
02541             MathLib::isNegative(tok->strAt(2))) {
02542             cctypefunctionCallError(tok, tok->str(), tok->strAt(2));
02543         }
02544     }
02545 }
02546 void CheckOther::cctypefunctionCallError(const Token *tok, const std::string &functionName, const std::string &value)
02547 {
02548     reportError(tok, Severity::error, "wrongcctypecall", "Passing value " + value + " to " + functionName + "() causes undefined behavior which may lead to a crash.");
02549 }
02550 
02551 //---------------------------------------------------------------------------
02552 //---------------------------------------------------------------------------
02553 void CheckOther::checkMisusedScopedObject()
02554 {
02555     // Skip this check for .c files
02556     if (_tokenizer->isC()) {
02557         return;
02558     }
02559 
02560     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
02561     const std::size_t functions = symbolDatabase->functionScopes.size();
02562     for (std::size_t i = 0; i < functions; ++i) {
02563         const Scope * scope = symbolDatabase->functionScopes[i];
02564         for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
02565             if (Token::Match(tok, "[;{}] %var% (")
02566                 && Token::simpleMatch(tok->linkAt(2), ") ;")
02567                 && symbolDatabase->isClassOrStruct(tok->next()->str())
02568                 && !tok->next()->function()) {
02569                 tok = tok->next();
02570                 misusedScopeObjectError(tok, tok->str());
02571                 tok = tok->next();
02572             }
02573         }
02574     }
02575 }
02576 
02577 void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname)
02578 {
02579     reportError(tok, Severity::error,
02580                 "unusedScopedObject", "Instance of '" + varname + "' object is destroyed immediately.");
02581 }
02582 
02583 //-------------------------------------------------------------------------------
02584 // Comparing functions which are returning value of type bool
02585 //-------------------------------------------------------------------------------
02586 
02587 void CheckOther::checkComparisonOfFuncReturningBool()
02588 {
02589     if (!_settings->isEnabled("style"))
02590         return;
02591 
02592     if (!_tokenizer->isCPP())
02593         return;
02594 
02595     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
02596 
02597     const std::size_t functions = symbolDatabase->functionScopes.size();
02598     for (std::size_t i = 0; i < functions; ++i) {
02599         const Scope * scope = symbolDatabase->functionScopes[i];
02600         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02601             if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=")
02602                 continue;
02603             const Token *first_token;
02604             bool first_token_func_of_type_bool = false;
02605             if (tok->strAt(-1) == ")") {
02606                 first_token = tok->previous()->link()->previous();
02607             } else {
02608                 first_token = tok->previous();
02609             }
02610             if (Token::Match(first_token, "%var% (") && !Token::Match(first_token->previous(), "::|.")) {
02611                 const Function* func = first_token->function();
02612                 if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") {
02613                     first_token_func_of_type_bool = true;
02614                 }
02615             }
02616 
02617             Token *second_token = tok->next();
02618             bool second_token_func_of_type_bool = false;
02619             while (second_token->str()=="!") {
02620                 second_token = second_token->next();
02621             }
02622             if (Token::Match(second_token, "%var% (") && !Token::Match(second_token->previous(), "::|.")) {
02623                 const Function* func = second_token->function();
02624                 if (func && func->tokenDef && func->tokenDef->strAt(-1) == "bool") {
02625                     second_token_func_of_type_bool = true;
02626                 }
02627             }
02628 
02629             if ((first_token_func_of_type_bool == true) && (second_token_func_of_type_bool == true)) {
02630                 comparisonOfTwoFuncsReturningBoolError(first_token->next(), first_token->str(), second_token->str());
02631             } else if (first_token_func_of_type_bool == true) {
02632                 comparisonOfFuncReturningBoolError(first_token->next(), first_token->str());
02633             } else if (second_token_func_of_type_bool == true) {
02634                 comparisonOfFuncReturningBoolError(second_token->previous(), second_token->str());
02635             }
02636         }
02637     }
02638 }
02639 
02640 void CheckOther::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression)
02641 {
02642     reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError",
02643                 "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n"
02644                 "The return type of function '" + expression + "' is 'bool' "
02645                 "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)"
02646                 " operator could cause unexpected results.");
02647 }
02648 
02649 void CheckOther::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2)
02650 {
02651     reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError",
02652                 "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n"
02653                 "The return type of function '" + expression1 + "' and function '" + expression2 + "' is 'bool' "
02654                 "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)"
02655                 " operator could cause unexpected results.");
02656 }
02657 
02658 //-------------------------------------------------------------------------------
02659 // Comparison of bool with bool
02660 //-------------------------------------------------------------------------------
02661 
02662 void CheckOther::checkComparisonOfBoolWithBool()
02663 {
02664     // FIXME: This checking is "experimental" because of the false positives
02665     //        when self checking lib/tokenize.cpp (#2617)
02666     if (!_settings->experimental)
02667         return;
02668 
02669     if (!_settings->isEnabled("style"))
02670         return;
02671 
02672     if (!_tokenizer->isCPP())
02673         return;
02674 
02675     const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
02676 
02677     const std::size_t functions = symbolDatabase->functionScopes.size();
02678     for (std::size_t i = 0; i < functions; ++i) {
02679         const Scope * scope = symbolDatabase->functionScopes[i];
02680         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02681             if (tok->type() != Token::eComparisonOp || tok->str() == "==" || tok->str() == "!=")
02682                 continue;
02683             bool first_token_bool = false;
02684             bool second_token_bool = false;
02685 
02686             const Token *first_token = tok->previous();
02687             if (first_token->varId()) {
02688                 if (isBool(first_token->variable())) {
02689                     first_token_bool = true;
02690                 }
02691             }
02692             const Token *second_token = tok->next();
02693             if (second_token->varId()) {
02694                 if (isBool(second_token->variable())) {
02695                     second_token_bool = true;
02696                 }
02697             }
02698             if ((first_token_bool == true) && (second_token_bool == true)) {
02699                 comparisonOfBoolWithBoolError(first_token->next(), first_token->str());
02700             }
02701         }
02702     }
02703 }
02704 
02705 void CheckOther::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression)
02706 {
02707     reportError(tok, Severity::style, "comparisonOfBoolWithBoolError",
02708                 "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n"
02709                 "The variable '" + expression + "' is of type 'bool' "
02710                 "and comparing 'bool' value using relational (<, >, <= or >=)"
02711                 " operator could cause unexpected results.");
02712 }
02713 
02714 //---------------------------------------------------------------------------
02715 //---------------------------------------------------------------------------
02716 void CheckOther::checkIncorrectStringCompare()
02717 {
02718     if (!_settings->isEnabled("warning"))
02719         return;
02720 
02721     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02722     const std::size_t functions = symbolDatabase->functionScopes.size();
02723     for (std::size_t i = 0; i < functions; ++i) {
02724         const Scope * scope = symbolDatabase->functionScopes[i];
02725         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
02726             // skip "assert(str && ..)" and "assert(.. && str)"
02727             if (Token::Match(tok, "%var% (") &&
02728                 (Token::Match(tok->tokAt(2), "%str% &&") || Token::Match(tok->next()->link()->tokAt(-2), "&& %str% )")) &&
02729                 (tok->str().find("assert")+6U==tok->str().size() || tok->str().find("ASSERT")+6U==tok->str().size()))
02730                 tok = tok->next()->link();
02731 
02732             if (Token::Match(tok, ". substr ( %any% , %num% ) ==|!= %str%")) {
02733                 MathLib::bigint clen = MathLib::toLongNumber(tok->strAt(5));
02734                 std::size_t slen = Token::getStrLength(tok->tokAt(8));
02735                 if (clen != (int)slen) {
02736                     incorrectStringCompareError(tok->next(), "substr", tok->strAt(8));
02737                 }
02738             } else if (Token::Match(tok, "%str% ==|!= %var% . substr ( %any% , %num% )")) {
02739                 MathLib::bigint clen = MathLib::toLongNumber(tok->strAt(8));
02740                 std::size_t slen = Token::getStrLength(tok);
02741                 if (clen != (int)slen) {
02742                     incorrectStringCompareError(tok->next(), "substr", tok->str());
02743                 }
02744             } else if (Token::Match(tok, "&&|%oror%|( %str% &&|%oror%|)") && !Token::Match(tok, "( %str% )")) {
02745                 incorrectStringBooleanError(tok->next(), tok->strAt(1));
02746             } else if (Token::Match(tok, "if|while ( %str% )")) {
02747                 incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2));
02748             }
02749         }
02750     }
02751 }
02752 
02753 void CheckOther::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string)
02754 {
02755     reportError(tok, Severity::warning, "incorrectStringCompare", "String literal " + string + " doesn't match length argument for " + func + "().");
02756 }
02757 
02758 void CheckOther::incorrectStringBooleanError(const Token *tok, const std::string& string)
02759 {
02760     reportError(tok, Severity::warning, "incorrectStringBooleanError", "Conversion of string literal " + string + " to bool always evaluates to true.");
02761 }
02762 
02763 //-----------------------------------------------------------------------------
02764 // check for duplicate expressions in if statements
02765 // if (a) { } else if (a) { }
02766 //-----------------------------------------------------------------------------
02767 
02768 static bool expressionHasSideEffects(const Token *first, const Token *last)
02769 {
02770     for (const Token *tok = first; tok != last->next(); tok = tok->next()) {
02771         // check for assignment
02772         if (tok->isAssignmentOp())
02773             return true;
02774 
02775         // check for inc/dec
02776         else if (tok->type() == Token::eIncDecOp)
02777             return true;
02778 
02779         // check for function call
02780         else if (Token::Match(tok, "%var% (") &&
02781                  !(Token::Match(tok, "c_str|string") || tok->isStandardType()))
02782             return true;
02783     }
02784 
02785     return false;
02786 }
02787 
02788 void CheckOther::checkDuplicateIf()
02789 {
02790     if (!_settings->isEnabled("style"))
02791         return;
02792 
02793     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02794 
02795     for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
02796         const Token* const tok = scope->classDef;
02797         // only check if statements
02798         if (scope->type != Scope::eIf || !tok)
02799             continue;
02800 
02801         std::map<std::string, const Token*> expressionMap;
02802 
02803         // get the expression from the token stream
02804         std::string expression = tok->tokAt(2)->stringifyList(tok->next()->link());
02805 
02806         // save the expression and its location
02807         expressionMap.insert(std::make_pair(expression, tok));
02808 
02809         // find the next else if (...) statement
02810         const Token *tok1 = scope->classEnd;
02811 
02812         // check all the else if (...) statements
02813         while ((Token::simpleMatch(tok1, "} else if (") &&
02814                 Token::simpleMatch(tok1->linkAt(3), ") {")) ||
02815                (Token::simpleMatch(tok1, "} else { if (") &&
02816                 Token::simpleMatch(tok1->linkAt(4), ") {"))) {
02817             int conditionIndex=(tok1->strAt(3)=="(") ? 3 : 4;
02818             // get the expression from the token stream
02819             expression = tok1->tokAt(conditionIndex+1)->stringifyList(tok1->linkAt(conditionIndex));
02820 
02821             // try to look up the expression to check for duplicates
02822             std::map<std::string, const Token *>::iterator it = expressionMap.find(expression);
02823 
02824             // found a duplicate
02825             if (it != expressionMap.end()) {
02826                 // check for expressions that have side effects and ignore them
02827                 if (!expressionHasSideEffects(tok1->tokAt(conditionIndex+1), tok1->linkAt(conditionIndex)->previous()))
02828                     duplicateIfError(it->second, tok1->next());
02829             }
02830 
02831             // not a duplicate expression so save it and its location
02832             else
02833                 expressionMap.insert(std::make_pair(expression, tok1->next()));
02834 
02835             // find the next else if (...) statement
02836             tok1 = tok1->linkAt(conditionIndex)->next()->link();
02837         }
02838     }
02839 }
02840 
02841 void CheckOther::duplicateIfError(const Token *tok1, const Token *tok2)
02842 {
02843     std::list<const Token *> toks;
02844     toks.push_back(tok2);
02845     toks.push_back(tok1);
02846 
02847     reportError(toks, Severity::style, "duplicateIf", "Duplicate conditions in 'if' and related 'else if'.\n"
02848                 "Duplicate conditions in 'if' and related 'else if'. This is suspicious and might indicate "
02849                 "a cut and paste or logic error. Please examine this code carefully to determine "
02850                 "if it is correct.");
02851 }
02852 
02853 //-----------------------------------------------------------------------------
02854 // check for duplicate code in if and else branches
02855 // if (a) { b = true; } else { b = true; }
02856 //-----------------------------------------------------------------------------
02857 void CheckOther::checkDuplicateBranch()
02858 {
02859     if (!_settings->isEnabled("style"))
02860         return;
02861 
02862     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
02863 
02864     std::list<Scope>::const_iterator scope;
02865 
02866     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
02867         if (scope->type != Scope::eIf && scope->type != Scope::eElseIf)
02868             continue;
02869 
02870         // check all the code in the function for if (..) else
02871         if (Token::simpleMatch(scope->classEnd, "} else {")) {
02872             // Make sure there are no macros (different macros might be expanded
02873             // to the same code)
02874             bool macro = false;
02875             for (const Token *tok = scope->classStart; tok != scope->classEnd->linkAt(2); tok = tok->next()) {
02876                 if (tok->isExpandedMacro()) {
02877                     macro = true;
02878                     break;
02879                 }
02880             }
02881             if (macro)
02882                 continue;
02883 
02884             // save if branch code
02885             std::string branch1 = scope->classStart->next()->stringifyList(scope->classEnd);
02886 
02887             // save else branch code
02888             std::string branch2 = scope->classEnd->tokAt(3)->stringifyList(scope->classEnd->linkAt(2));
02889 
02890             // check for duplicates
02891             if (branch1 == branch2)
02892                 duplicateBranchError(scope->classDef, scope->classEnd->next());
02893         }
02894     }
02895 }
02896 
02897 void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2)
02898 {
02899     std::list<const Token *> toks;
02900     toks.push_back(tok2);
02901     toks.push_back(tok1);
02902 
02903     reportError(toks, Severity::style, "duplicateBranch", "Found duplicate branches for 'if' and 'else'.\n"
02904                 "Finding the same code in an 'if' and related 'else' branch is suspicious and "
02905                 "might indicate a cut and paste or logic error. Please examine this code "
02906                 "carefully to determine if it is correct.");
02907 }
02908 
02909 
02910 //-----------------------------------------------------------------------------
02911 // Check for a free() of an invalid address
02912 // char* p = malloc(100);
02913 // free(p + 10);
02914 //-----------------------------------------------------------------------------
02915 void CheckOther::checkInvalidFree()
02916 {
02917     std::map<unsigned int, bool> allocatedVariables;
02918     for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
02919 
02920         // Keep track of which variables were assigned addresses to newly-allocated memory
02921         if (Token::Match(tok, "%var% = malloc|g_malloc|new")) {
02922             allocatedVariables.insert(std::make_pair(tok->varId(), false));
02923         }
02924 
02925         // If a previously-allocated pointer is incremented or decremented, any subsequent
02926         // free involving pointer arithmetic may or may not be invalid, so we should only
02927         // report an inconclusive result.
02928         else if (Token::Match(tok, "%var% = %var% +|-") &&
02929                  tok->varId() == tok->tokAt(2)->varId() &&
02930                  allocatedVariables.find(tok->varId()) != allocatedVariables.end()) {
02931             if (_settings->inconclusive)
02932                 allocatedVariables[tok->varId()] = true;
02933             else
02934                 allocatedVariables.erase(tok->varId());
02935         }
02936 
02937         // If a previously-allocated pointer is assigned a completely new value,
02938         // we can't know if any subsequent free() on that pointer is valid or not.
02939         else if (Token::Match(tok, "%var% = ")) {
02940             allocatedVariables.erase(tok->varId());
02941         }
02942 
02943         // If a variable that was previously assigned a newly-allocated memory location is
02944         // added or subtracted from when used to free the memory, report an error.
02945         else if (Token::Match(tok, "free|g_free|delete ( %any% +|- %any%") ||
02946                  Token::Match(tok, "delete [ ] ( %any% +|- %any%") ||
02947                  Token::Match(tok, "delete %any% +|- %any%")) {
02948 
02949             const int varIdx = tok->strAt(1) == "(" ? 2 :
02950                                tok->strAt(3) == "(" ? 4 : 1;
02951             const unsigned int var1 = tok->tokAt(varIdx)->varId();
02952             const unsigned int var2 = tok->tokAt(varIdx + 2)->varId();
02953             const std::map<unsigned int, bool>::iterator alloc1 = allocatedVariables.find(var1);
02954             const std::map<unsigned int, bool>::iterator alloc2 = allocatedVariables.find(var2);
02955             if (alloc1 != allocatedVariables.end()) {
02956                 invalidFreeError(tok, alloc1->second);
02957             } else if (alloc2 != allocatedVariables.end()) {
02958                 invalidFreeError(tok, alloc2->second);
02959             }
02960         }
02961 
02962         // If the previously-allocated variable is passed in to another function
02963         // as a parameter, it might be modified, so we shouldn't report an error
02964         // if it is later used to free memory
02965         else if (Token::Match(tok, "%var% (")) {
02966             const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1));
02967             while (tok2 != NULL) {
02968                 allocatedVariables.erase(tok2->varId());
02969                 tok2 = Token::findmatch(tok2->next(), "%var%", tok->linkAt(1));
02970             }
02971         }
02972     }
02973 }
02974 
02975 void CheckOther::invalidFreeError(const Token *tok, bool inconclusive)
02976 {
02977     reportError(tok, Severity::error, "invalidFree", "Invalid memory address freed.", inconclusive);
02978 }
02979 
02980 
02981 //-----------------------------------------------------------------------------
02982 // Check for double free
02983 // free(p); free(p);
02984 //-----------------------------------------------------------------------------
02985 void CheckOther::checkDoubleFree()
02986 {
02987     std::set<unsigned int> freedVariables;
02988     std::set<unsigned int> closeDirVariables;
02989 
02990     for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
02991         // Keep track of any variables passed to "free()", "g_free()" or "closedir()",
02992         // and report an error if the same variable is passed twice.
02993         if (Token::Match(tok, "free|g_free|closedir ( %var% )")) {
02994             unsigned int var = tok->tokAt(2)->varId();
02995             if (var) {
02996                 if (Token::Match(tok, "free|g_free")) {
02997                     if (freedVariables.find(var) != freedVariables.end())
02998                         doubleFreeError(tok, tok->strAt(2));
02999                     else
03000                         freedVariables.insert(var);
03001                 } else if (tok->str() == "closedir") {
03002                     if (closeDirVariables.find(var) != closeDirVariables.end())
03003                         doubleCloseDirError(tok, tok->strAt(2));
03004                     else
03005                         closeDirVariables.insert(var);
03006                 }
03007             }
03008         }
03009 
03010         // Keep track of any variables operated on by "delete" or "delete[]"
03011         // and report an error if the same variable is delete'd twice.
03012         else if (Token::Match(tok, "delete %var% ;") || Token::Match(tok, "delete [ ] %var% ;")) {
03013             int varIdx = (tok->strAt(1) == "[") ? 3 : 1;
03014             unsigned int var = tok->tokAt(varIdx)->varId();
03015             if (var) {
03016                 if (freedVariables.find(var) != freedVariables.end())
03017                     doubleFreeError(tok, tok->strAt(varIdx));
03018                 else
03019                     freedVariables.insert(var);
03020             }
03021         }
03022 
03023         // If this scope doesn't return, clear the set of previously freed variables
03024         else if (tok->str() == "}" && _tokenizer->IsScopeNoReturn(tok)) {
03025             freedVariables.clear();
03026             closeDirVariables.clear();
03027         }
03028 
03029         // If this scope is a "for" or "while" loop that contains "break" or "continue",
03030         // give up on trying to figure out the flow of execution and just clear the set
03031         // of previously freed variables.
03032         // TODO: There are false negatives. This bailout is only needed when the
03033         // loop will exit without free()'ing the memory on the last iteration.
03034         else if (tok->str() == "}" && tok->link() && tok->link()->previous() &&
03035                  tok->link()->linkAt(-1) &&
03036                  Token::Match(tok->link()->linkAt(-1)->previous(), "while|for") &&
03037                  Token::findmatch(tok->link()->linkAt(-1), "break|continue ;", tok) != NULL) {
03038             freedVariables.clear();
03039             closeDirVariables.clear();
03040         }
03041 
03042         // If a variable is passed to a function, remove it from the set of previously freed variables
03043         else if (Token::Match(tok, "%var% (") && !Token::Match(tok, "printf|sprintf|snprintf|fprintf|wprintf|swprintf|fwprintf")) {
03044 
03045             // If this is a new function definition, clear all variables
03046             if (Token::simpleMatch(tok->next()->link(), ") {")) {
03047                 freedVariables.clear();
03048                 closeDirVariables.clear();
03049             }
03050             // If it is a function call, then clear those variables in its argument list
03051             else if (Token::simpleMatch(tok->next()->link(), ") ;")) {
03052                 for (const Token* tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
03053                     if (tok2->varId()) {
03054                         unsigned int var = tok2->varId();
03055                         freedVariables.erase(var);
03056                         closeDirVariables.erase(var);
03057                     }
03058                 }
03059             }
03060         }
03061 
03062         // If a pointer is assigned a new value, remove it from the set of previously freed variables
03063         else if (Token::Match(tok, "%var% =")) {
03064             unsigned int var = tok->varId();
03065             if (var) {
03066                 freedVariables.erase(var);
03067                 closeDirVariables.erase(var);
03068             }
03069         }
03070 
03071         // Any control statements in-between delete, free() or closedir() statements
03072         // makes it unclear whether any subsequent statements would be redundant.
03073         if (Token::Match(tok, "if|else|for|while|break|continue|goto|return|throw|switch")) {
03074             freedVariables.clear();
03075             closeDirVariables.clear();
03076         }
03077     }
03078 }
03079 
03080 void CheckOther::doubleFreeError(const Token *tok, const std::string &varname)
03081 {
03082     reportError(tok, Severity::error, "doubleFree", "Memory pointed to by '" + varname +"' is freed twice.");
03083 }
03084 
03085 void CheckOther::doubleCloseDirError(const Token *tok, const std::string &varname)
03086 {
03087     reportError(tok, Severity::error, "doubleCloseDir", "Directory handle '" + varname +"' closed twice.");
03088 }
03089 
03090 namespace {
03091     struct ExpressionTokens {
03092         const Token *start;
03093         const Token *end;
03094         int count;
03095         bool inconclusiveFunction;
03096         ExpressionTokens(const Token *s, const Token *e): start(s), end(e), count(1), inconclusiveFunction(false) {}
03097     };
03098 
03099     struct FuncFilter {
03100         FuncFilter(const Scope *scope, const Token *tok): _scope(scope), _tok(tok) {}
03101 
03102         bool operator()(const Function* func) const {
03103             bool matchingFunc = func->type == Function::eFunction &&
03104                                 _tok->str() == func->token->str();
03105             // either a class function, or a global function with the same name
03106             return (_scope && _scope == func->nestedIn && matchingFunc) ||
03107                    (!_scope && matchingFunc);
03108         }
03109         const Scope *_scope;
03110         const Token *_tok;
03111     };
03112 
03113     bool inconclusiveFunctionCall(const std::list<const Function*> &constFunctions,
03114                                   const ExpressionTokens &tokens)
03115     {
03116         const Token *start = tokens.start;
03117         const Token *end = tokens.end;
03118         // look for function calls between start and end...
03119         for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
03120             if (tok != start && tok->str() == "(") {
03121                 // go back to find the function call.
03122                 const Token *prev = tok->previous();
03123                 if (!prev)
03124                     continue;
03125                 if (prev->str() == ">") {
03126                     // ignore template functions like boo<double>()
03127                     return true;
03128                 }
03129                 if (prev->isName()) {
03130                     const Variable *v = 0;
03131                     if (Token::Match(prev->tokAt(-2), "%var% .")) {
03132                         const Token *scope = prev->tokAt(-2);
03133                         v = scope->variable();
03134                     }
03135                     // hard coded list of safe, no-side-effect functions
03136                     if (v == 0 && Token::Match(prev, "strcmp|strncmp|strlen|wcscmp|wcsncmp|wcslen|memcmp|strcasecmp|strncasecmp"))
03137                         return false;
03138                     std::list<const Function*>::const_iterator it = std::find_if(constFunctions.begin(),
03139                             constFunctions.end(),
03140                             FuncFilter(v ? v->typeScope(): 0, prev));
03141                     if (it == constFunctions.end())
03142                         return true;
03143                 }
03144             }
03145         }
03146         return false;
03147     }
03148 
03149     class Expressions {
03150     public:
03151         Expressions(const std::list<const Function*> &constFunctions)
03152             : _start(0),
03153               _lastTokens(0),
03154               _constFunctions(constFunctions) { }
03155 
03156         void endExpr(const Token *end) {
03157             const std::string &e = _expression.str();
03158             if (!e.empty()) {
03159                 std::map<std::string, ExpressionTokens>::iterator it = _expressions.find(e);
03160                 bool lastInconclusive = _lastTokens && _lastTokens->inconclusiveFunction;
03161                 if (it == _expressions.end()) {
03162                     ExpressionTokens exprTokens(_start, end);
03163                     exprTokens.inconclusiveFunction = lastInconclusive || inconclusiveFunctionCall(
03164                                                           _constFunctions, exprTokens);
03165                     _expressions.insert(std::make_pair(e, exprTokens));
03166                     _lastTokens = &_expressions.find(e)->second;
03167                 } else {
03168                     ExpressionTokens &expr = it->second;
03169                     expr.count += 1;
03170                     expr.inconclusiveFunction = expr.inconclusiveFunction || lastInconclusive;
03171                     _lastTokens = &expr;
03172                 }
03173             }
03174             _expression.str("");
03175             _start = 0;
03176         }
03177 
03178         void append(const Token *tok) {
03179             if (!_start)
03180                 _start = tok;
03181             _expression << tok->str();
03182         }
03183 
03184         std::map<std::string,ExpressionTokens> &getMap() {
03185             return _expressions;
03186         }
03187 
03188     private:
03189         std::map<std::string, ExpressionTokens> _expressions;
03190         std::ostringstream _expression;
03191         const Token *_start;
03192         ExpressionTokens *_lastTokens;
03193         const std::list<const Function*> &_constFunctions;
03194     };
03195 
03196     bool notconst(const Function* func)
03197     {
03198         return !func->isConst;
03199     }
03200 
03201     void getConstFunctions(const SymbolDatabase *symbolDatabase, std::list<const Function*> &constFunctions)
03202     {
03203         std::list<Scope>::const_iterator scope;
03204         for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
03205             std::list<Function>::const_iterator func;
03206             // only add const functions that do not have a non-const overloaded version
03207             // since it is pretty much impossible to tell which is being called.
03208             typedef std::map<std::string, std::list<const Function*> > StringFunctionMap;
03209             StringFunctionMap functionsByName;
03210             for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
03211                 functionsByName[func->tokenDef->str()].push_back(&*func);
03212             }
03213             for (StringFunctionMap::iterator it = functionsByName.begin();
03214                  it != functionsByName.end(); ++it) {
03215                 std::list<const Function*>::const_iterator nc = std::find_if(it->second.begin(), it->second.end(), notconst);
03216                 if (nc == it->second.end()) {
03217                     // ok to add all of them
03218                     constFunctions.splice(constFunctions.end(), it->second);
03219                 }
03220             }
03221         }
03222     }
03223 
03224 }
03225 
03226 void CheckOther::checkExpressionRange(const std::list<const Function*> &constFunctions,
03227                                       const Token *start,
03228                                       const Token *end,
03229                                       const std::string &toCheck)
03230 {
03231     if (!start || !end)
03232         return;
03233     Expressions expressions(constFunctions);
03234     std::string opName;
03235     int level = 0;
03236     for (const Token *tok = start->next(); tok && tok != end; tok = tok->next()) {
03237         if (tok->str() == ")")
03238             level--;
03239         else if (tok->str() == "(")
03240             level++;
03241 
03242         if (level == 0 && Token::Match(tok, toCheck.c_str())) {
03243             opName = tok->str();
03244             expressions.endExpr(tok);
03245         } else {
03246             expressions.append(tok);
03247         }
03248     }
03249     expressions.endExpr(end);
03250     std::map<std::string,ExpressionTokens>::const_iterator it = expressions.getMap().begin();
03251     for (; it != expressions.getMap().end(); ++it) {
03252         // check expression..
03253         bool valid = true;
03254         unsigned int parentheses = 0;  // ()
03255         unsigned int brackets = 0;     // []
03256 
03257         // taking address?
03258         if (Token::Match(it->second.end->previous(), "%op% &")) {
03259             continue;
03260         }
03261 
03262         for (const Token *tok = it->second.start; tok && tok != it->second.end; tok = tok->next()) {
03263             if (tok->str() == "(") {
03264                 ++parentheses;
03265             } else if (tok->str() == ")") {
03266                 if (parentheses == 0) {
03267                     valid = false;
03268                     break;
03269                 }
03270                 --parentheses;
03271             } else if (tok->str() == "[") {
03272                 ++brackets;
03273             } else if (tok->str() == "]") {
03274                 if (brackets == 0) {
03275                     valid = false;
03276                     break;
03277                 }
03278                 --brackets;
03279             } else if (tok->type() == Token::eIncDecOp) {
03280                 valid = false;
03281                 break;
03282             }
03283         }
03284 
03285         if (!valid || parentheses!=0 || brackets!=0)
03286             continue;
03287 
03288         const ExpressionTokens &expr = it->second;
03289         if (expr.count > 1 && !expr.inconclusiveFunction) {
03290             duplicateExpressionError(expr.start, expr.start, opName);
03291         }
03292     }
03293 }
03294 
03295 void CheckOther::complexDuplicateExpressionCheck(const std::list<const Function*> &constFunctions,
03296         const Token *classStart,
03297         const std::string &toCheck,
03298         const std::string &alt)
03299 {
03300     std::string statementStart(",|=|?|:|return");
03301     if (!alt.empty())
03302         statementStart += "|" + alt;
03303     std::string statementEnd(";|,|?|:");
03304     if (!alt.empty())
03305         statementEnd += "|" + alt;
03306 
03307     for (const Token *tok = classStart; tok && tok != classStart->link(); tok = tok->next()) {
03308         if (!Token::Match(tok, toCheck.c_str()))
03309             continue;
03310 
03311         // look backward for the start of the statement
03312         const Token *start = 0;
03313         int level = 0;
03314         for (const Token *tok1 = tok->previous(); tok1 && tok1 != classStart; tok1 = tok1->previous()) {
03315             if (tok1->str() == ")")
03316                 level++;
03317             else if (tok1->str() == "(")
03318                 level--;
03319 
03320             if (level < 0 || (level == 0 && Token::Match(tok1, statementStart.c_str()))) {
03321                 start = tok1;
03322                 break;
03323             }
03324         }
03325         const Token *end = 0;
03326         level = 0;
03327         // look for the end of the statement
03328         for (const Token *tok1 = tok->next(); tok1 && tok1 != classStart->link(); tok1 = tok1->next()) {
03329             if (tok1->str() == ")")
03330                 level--;
03331             else if (tok1->str() == "(")
03332                 level++;
03333 
03334             if (level < 0 || (level == 0 && Token::Match(tok1, statementEnd.c_str()))) {
03335                 end = tok1;
03336                 break;
03337             }
03338         }
03339         checkExpressionRange(constFunctions, start, end, toCheck);
03340     }
03341 }
03342 
03343 //---------------------------------------------------------------------------
03344 // check for the same expression on both sides of an operator
03345 // (x == x), (x && x), (x || x)
03346 // (x.y == x.y), (x.y && x.y), (x.y || x.y)
03347 //---------------------------------------------------------------------------
03348 void CheckOther::checkDuplicateExpression()
03349 {
03350     if (!_settings->isEnabled("style"))
03351         return;
03352 
03353     // Parse all executing scopes..
03354     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03355 
03356     std::list<Scope>::const_iterator scope;
03357     std::list<const Function*> constFunctions;
03358     getConstFunctions(symbolDatabase, constFunctions);
03359 
03360     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
03361         // only check functions
03362         if (scope->type != Scope::eFunction)
03363             continue;
03364 
03365         complexDuplicateExpressionCheck(constFunctions, scope->classStart, "%or%", "");
03366         complexDuplicateExpressionCheck(constFunctions, scope->classStart, "%oror%", "");
03367         complexDuplicateExpressionCheck(constFunctions, scope->classStart, "&", "%oror%|%or%");
03368         complexDuplicateExpressionCheck(constFunctions, scope->classStart, "&&", "%oror%|%or%");
03369 
03370         for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
03371             if (Token::Match(tok, ",|=|return|(|&&|%oror% %var% %comp%|- %var% )|&&|%oror%|;|,") &&
03372                 tok->strAt(1) == tok->strAt(3)) {
03373                 // float == float and float != float are valid NaN checks
03374                 // float - float is a valid Inf check
03375                 if (Token::Match(tok->tokAt(2), "==|!=|-") && tok->next()->varId()) {
03376                     const Variable *var = tok->next()->variable();
03377                     if (var && var->typeStartToken() == var->typeEndToken()) {
03378                         if (Token::Match(var->typeStartToken(), "float|double"))
03379                             continue;
03380                     }
03381                 }
03382 
03383                 // If either variable token is an expanded macro then
03384                 // don't write the warning
03385                 if (tok->next()->isExpandedMacro() || tok->tokAt(3)->isExpandedMacro())
03386                     continue;
03387 
03388                 duplicateExpressionError(tok->next(), tok->tokAt(3), tok->strAt(2));
03389             } else if (Token::Match(tok, ",|=|return|(|&&|%oror% %var% . %var% %comp%|- %var% . %var% )|&&|%oror%|;|,") &&
03390                        tok->strAt(1) == tok->strAt(5) && tok->strAt(3) == tok->strAt(7)) {
03391 
03392                 // If either variable token is an expanded macro then
03393                 // don't write the warning
03394                 if (tok->next()->isExpandedMacro() || tok->tokAt(6)->isExpandedMacro())
03395                     continue;
03396 
03397                 duplicateExpressionError(tok->next(), tok->tokAt(6), tok->strAt(4));
03398             }
03399         }
03400     }
03401 }
03402 
03403 void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op)
03404 {
03405     std::list<const Token *> toks;
03406     toks.push_back(tok2);
03407     toks.push_back(tok1);
03408 
03409     reportError(toks, Severity::style, "duplicateExpression", "Same expression on both sides of \'" + op + "\'.\n"
03410                 "Finding the same expression on both sides of an operator is suspicious and might "
03411                 "indicate a cut and paste or logic error. Please examine this code carefully to "
03412                 "determine if it is correct.");
03413 }
03414 
03415 //---------------------------------------------------------------------------
03416 // Check for string comparison involving two static strings.
03417 // if(strcmp("00FF00","00FF00")==0) // <- statement is always true
03418 //---------------------------------------------------------------------------
03419 void CheckOther::checkAlwaysTrueOrFalseStringCompare()
03420 {
03421     if (!_settings->isEnabled("warning"))
03422         return;
03423 
03424     const Token *tok = _tokenizer->tokens();
03425     while (tok && (tok = Token::findmatch(tok, "strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp|wcsncmp ( %str% , %str% ")) != NULL) {
03426         const std::string &str1 = tok->strAt(2);
03427         const std::string &str2 = tok->strAt(4);
03428         alwaysTrueFalseStringCompareError(tok, str1, str2);
03429         tok = tok->tokAt(5);
03430     }
03431 
03432     tok = _tokenizer->tokens();
03433     while (tok && (tok = Token::findmatch(tok, "QString :: compare ( %str% , %str% )")) != NULL) {
03434         const std::string &str1 = tok->strAt(4);
03435         const std::string &str2 = tok->strAt(6);
03436         alwaysTrueFalseStringCompareError(tok, str1, str2);
03437         tok = tok->tokAt(7);
03438     }
03439 
03440     tok = _tokenizer->tokens();
03441     while (tok && (tok = Token::findmatch(tok, "strncmp|strcmp|stricmp|strcmpi|strcasecmp|wcscmp|wcsncmp ( %var% , %var% ")) != NULL) {
03442         const std::string &str1 = tok->strAt(2);
03443         const std::string &str2 = tok->strAt(4);
03444         if (str1 == str2)
03445             alwaysTrueStringVariableCompareError(tok, str1, str2);
03446         tok = tok->tokAt(5);
03447     }
03448 
03449     tok = _tokenizer->tokens();
03450     while (tok && (tok = Token::findmatch(tok, "!!+ %str% ==|!= %str% !!+")) != NULL) {
03451         const std::string &str1 = tok->strAt(1);
03452         const std::string &str2 = tok->strAt(3);
03453         alwaysTrueFalseStringCompareError(tok, str1, str2);
03454         tok = tok->tokAt(5);
03455     }
03456 }
03457 
03458 void CheckOther::alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2)
03459 {
03460     const std::size_t stringLen = 10;
03461     const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + "..");
03462     const std::string string2 = (str2.size() < stringLen) ? str2 : (str2.substr(0, stringLen-2) + "..");
03463 
03464     reportError(tok, Severity::warning, "staticStringCompare",
03465                 "Unnecessary comparison of static strings.\n"
03466                 "The compared strings, '" + string1 + "' and '" + string2 + "', are always " + (str1==str2?"identical":"unequal") + ". "
03467                 "Therefore the comparison is unnecessary and looks suspicious.");
03468 }
03469 
03470 void CheckOther::alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2)
03471 {
03472     reportError(tok, Severity::warning, "stringCompare",
03473                 "Comparison of identical string variables.\n"
03474                 "The compared strings, '" + str1 + "' and '" + str2 + "', are identical. "
03475                 "This could be a logic bug.");
03476 }
03477 
03478 
03479 //-----------------------------------------------------------------------------
03480 //-----------------------------------------------------------------------------
03481 void CheckOther::checkSuspiciousStringCompare()
03482 {
03483     if (!_settings->isEnabled("warning"))
03484         return;
03485 
03486     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
03487     const std::size_t functions = symbolDatabase->functionScopes.size();
03488     for (std::size_t i = 0; i < functions; ++i) {
03489         const Scope * scope = symbolDatabase->functionScopes[i];
03490         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03491             if (tok->next()->type() != Token::eComparisonOp)
03492                 continue;
03493 
03494             const Token* varTok = tok;
03495             const Token* litTok = tok->tokAt(2);
03496 
03497             if (varTok->strAt(-1) == "+" || litTok->strAt(1) == "+")
03498                 continue;
03499 
03500             if ((varTok->type() == Token::eString || varTok->type() == Token::eVariable) && (litTok->type() == Token::eString || litTok->type() == Token::eVariable) && litTok->type() != varTok->type()) {
03501                 if (varTok->type() == Token::eString)
03502                     std::swap(varTok, litTok);
03503 
03504                 const Variable *var = varTok->variable();
03505                 if (var) {
03506                     if (_tokenizer->isC() ||
03507                         (var->isPointer() && varTok->strAt(-1) != "*" && !Token::Match(varTok->next(), "[.([]")))
03508                         suspiciousStringCompareError(tok, var->name());
03509                 }
03510             }
03511         }
03512     }
03513 }
03514 
03515 void CheckOther::suspiciousStringCompareError(const Token* tok, const std::string& var)
03516 {
03517     reportError(tok, Severity::warning, "literalWithCharPtrCompare",
03518                 "String literal compared with variable '" + var + "'. Did you intend to use strcmp() instead?");
03519 }
03520 
03521 
03522 //-----------------------------------------------------------------------------
03523 //-----------------------------------------------------------------------------
03524 void CheckOther::checkModuloAlwaysTrueFalse()
03525 {
03526     if (!_settings->isEnabled("warning"))
03527         return;
03528 
03529     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03530     const std::size_t functions = symbolDatabase->functionScopes.size();
03531     for (std::size_t i = 0; i < functions; ++i) {
03532         const Scope * scope = symbolDatabase->functionScopes[i];
03533         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03534             if ((Token::Match(tok, "% %num% %comp% %num%")) &&
03535                 (!tok->tokAt(4) || !tok->tokAt(4)->isArithmeticalOp())) {
03536                 if (MathLib::isLessEqual(tok->strAt(1), tok->strAt(3)))
03537                     moduloAlwaysTrueFalseError(tok, tok->strAt(1));
03538             }
03539         }
03540     }
03541 }
03542 
03543 void CheckOther::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal)
03544 {
03545     reportError(tok, Severity::warning, "moduloAlwaysTrueFalse",
03546                 "Comparison of modulo result is predetermined, because it is always less than " + maxVal + ".");
03547 }
03548 
03549 //-----------------------------------------------------------------------------
03550 //-----------------------------------------------------------------------------
03551 void CheckOther::sizeofsizeof()
03552 {
03553     if (!_settings->isEnabled("warning"))
03554         return;
03555 
03556     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
03557         if (Token::Match(tok, "sizeof (| sizeof")) {
03558             sizeofsizeofError(tok);
03559             tok = tok->next();
03560         }
03561     }
03562 }
03563 
03564 void CheckOther::sizeofsizeofError(const Token *tok)
03565 {
03566     reportError(tok, Severity::warning,
03567                 "sizeofsizeof", "Calling 'sizeof' on 'sizeof'.\n"
03568                 "Calling sizeof for 'sizeof looks like a suspicious code and "
03569                 "most likely there should be just one 'sizeof'. The current "
03570                 "code is equivalent to 'sizeof(size_t)'");
03571 }
03572 
03573 //-----------------------------------------------------------------------------
03574 //-----------------------------------------------------------------------------
03575 void CheckOther::sizeofCalculation()
03576 {
03577     if (!_settings->isEnabled("warning"))
03578         return;
03579 
03580     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
03581         if (Token::simpleMatch(tok, "sizeof (")) {
03582             const Token* const end = tok->linkAt(1);
03583             for (const Token *tok2 = tok->tokAt(2); tok2 != end; tok2 = tok2->next()) {
03584                 if (tok2->isConstOp() && (!tok2->isExpandedMacro() || _settings->inconclusive) && !Token::Match(tok2, ">|<|&") && (Token::Match(tok2->previous(), "%var%") || tok2->str() != "*")) {
03585                     if (!(Token::Match(tok2->previous(), "%type%") || Token::Match(tok2->next(), "%type%"))) {
03586                         sizeofCalculationError(tok2, tok2->isExpandedMacro());
03587                         break;
03588                     }
03589                 } else if (tok2->type() == Token::eIncDecOp)
03590                     sizeofCalculationError(tok2, tok2->isExpandedMacro());
03591             }
03592         }
03593     }
03594 }
03595 
03596 void CheckOther::sizeofCalculationError(const Token *tok, bool inconclusive)
03597 {
03598     reportError(tok, Severity::warning,
03599                 "sizeofCalculation", "Found calculation inside sizeof().", inconclusive);
03600 }
03601 
03602 //-----------------------------------------------------------------------------
03603 // Check for code like:
03604 // seteuid(geteuid()) or setuid(getuid()), which first gets and then sets the
03605 // (effective) user id to itself. Very often this indicates a copy and paste
03606 // error.
03607 //-----------------------------------------------------------------------------
03608 void CheckOther::redundantGetAndSetUserId()
03609 {
03610     if (_settings->isEnabled("warning")
03611         && _settings->standards.posix) {
03612 
03613         for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
03614             if (Token::simpleMatch(tok, "setuid ( getuid ( ) )")
03615                 ||  Token::simpleMatch(tok, "seteuid ( geteuid ( ) )")
03616                 ||  Token::simpleMatch(tok, "setgid ( getgid ( ) )")
03617                 ||  Token::simpleMatch(tok, "setegid ( getegid ( ) )")) {
03618                 redundantGetAndSetUserIdError(tok);
03619             }
03620         }
03621     }
03622 }
03623 void CheckOther::redundantGetAndSetUserIdError(const Token *tok)
03624 {
03625     reportError(tok, Severity::warning,
03626                 "redundantGetAndSetUserId", "Redundant get and set of user id.\n"
03627                 "Redundant statement without any effect. First the user id is retrieved"
03628                 "by get(e)uid() and then set with set(e)uid().", false);
03629 }
03630 
03631 //-----------------------------------------------------------------------------
03632 // Check for code like sizeof()*sizeof() or sizeof(ptr)/value
03633 //-----------------------------------------------------------------------------
03634 void CheckOther::suspiciousSizeofCalculation()
03635 {
03636     if (!_settings->isEnabled("warning") || !_settings->inconclusive)
03637         return;
03638 
03639     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
03640         if (Token::simpleMatch(tok, "sizeof (")) {
03641             const Token* const end = tok->linkAt(1);
03642             const Variable* var = end->previous()->variable();
03643             if (end->strAt(-1) == "*" || (var && var->isPointer() && !var->isArray())) {
03644                 if (end->strAt(1) == "/")
03645                     divideSizeofError(tok);
03646             } else if (Token::simpleMatch(end, ") * sizeof"))
03647                 multiplySizeofError(tok);
03648         }
03649     }
03650 }
03651 
03652 void CheckOther::multiplySizeofError(const Token *tok)
03653 {
03654     reportError(tok, Severity::warning,
03655                 "multiplySizeof", "Multiplying sizeof() with sizeof() indicates a logic error.", true);
03656 }
03657 
03658 void CheckOther::divideSizeofError(const Token *tok)
03659 {
03660     reportError(tok, Severity::warning,
03661                 "divideSizeof", "Division of result of sizeof() on pointer type.\n"
03662                 "Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, "
03663                 "not the size of the memory area it points to.", true);
03664 }
03665 
03666 //-----------------------------------------------------------------------------
03667 //-----------------------------------------------------------------------------
03668 void CheckOther::checkAssignBoolToPointer()
03669 {
03670     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03671     const std::size_t functions = symbolDatabase->functionScopes.size();
03672     for (std::size_t i = 0; i < functions; ++i) {
03673         const Scope * scope = symbolDatabase->functionScopes[i];
03674         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
03675             if (Token::Match(tok, "!!* %var% = %bool% ;")) {
03676                 const Variable *var1(tok->next()->variable());
03677 
03678                 // Is variable a pointer?
03679                 if (var1 && var1->isPointer())
03680                     assignBoolToPointerError(tok->next());
03681             }
03682         }
03683     }
03684 }
03685 
03686 void CheckOther::assignBoolToPointerError(const Token *tok)
03687 {
03688     reportError(tok, Severity::error, "assignBoolToPointer",
03689                 "Boolean value assigned to pointer.");
03690 }
03691 
03692 //-----------------------------------------------------------------------------
03693 //-----------------------------------------------------------------------------
03694 void CheckOther::checkComparisonOfBoolExpressionWithInt()
03695 {
03696     if (!_settings->isEnabled("warning"))
03697         return;
03698 
03699     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
03700 
03701     const std::size_t functions = symbolDatabase->functionScopes.size();
03702     for (std::size_t i = 0; i < functions; ++i) {
03703         const Scope * scope = symbolDatabase->functionScopes[i];
03704         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03705             // Skip template parameters
03706             if (tok->str() == "<" && tok->link()) {
03707                 tok = tok->link();
03708                 continue;
03709             }
03710 
03711             const Token* numTok = 0;
03712             const Token* opTok = 0;
03713             char op = 0;
03714             if (Token::Match(tok, "&&|%oror% %any% ) %comp% %any%")) {
03715                 numTok = tok->tokAt(4);
03716                 opTok = tok->tokAt(3);
03717                 if (Token::Match(opTok, "<|>"))
03718                     op = opTok->str()[0];
03719             } else if (Token::Match(tok, "%any% %comp% ( %any% &&|%oror%")) {
03720                 numTok = tok;
03721                 opTok = tok->next();
03722                 if (Token::Match(opTok, "<|>"))
03723                     op = opTok->str()[0]=='>'?'<':'>';
03724             }
03725 
03726             else if (Token::Match(tok, "! %var% %comp% %any%")) {
03727                 numTok = tok->tokAt(3);
03728                 opTok = tok->tokAt(2);
03729                 if (Token::Match(opTok, "<|>"))
03730                     op = opTok->str()[0];
03731             } else if (Token::Match(tok, "%any% %comp% ! %var%")) {
03732                 numTok = tok;
03733                 opTok = tok->next();
03734                 if (Token::Match(opTok, "<|>"))
03735                     op = opTok->str()[0]=='>'?'<':'>';
03736             }
03737 
03738             if (numTok && opTok) {
03739                 if (numTok->isNumber()) {
03740                     if (((numTok->str() != "0" && numTok->str() != "1") || !Token::Match(opTok, "!=|==")) && !((op == '<' && numTok->str() == "1") || (op == '>' && numTok->str() == "0")))
03741                         comparisonOfBoolExpressionWithIntError(tok, true);
03742                 } else if (isNonBoolStdType(numTok->variable()))
03743                     comparisonOfBoolExpressionWithIntError(tok, false);
03744             }
03745         }
03746     }
03747 }
03748 
03749 void CheckOther::comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1)
03750 {
03751     if (n0o1)
03752         reportError(tok, Severity::warning, "compareBoolExpressionWithInt",
03753                     "Comparison of a boolean expression with an integer other than 0 or 1.");
03754     else
03755         reportError(tok, Severity::warning, "compareBoolExpressionWithInt",
03756                     "Comparison of a boolean expression with an integer.");
03757 }
03758 
03759 
03760 //---------------------------------------------------------------------------
03761 // Check testing sign of unsigned variables and pointers.
03762 //---------------------------------------------------------------------------
03763 void CheckOther::checkSignOfUnsignedVariable()
03764 {
03765     if (!_settings->isEnabled("style"))
03766         return;
03767 
03768     const bool inconclusive = _tokenizer->codeWithTemplates();
03769     if (inconclusive && !_settings->inconclusive)
03770         return;
03771 
03772     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03773 
03774     const std::size_t functions = symbolDatabase->functionScopes.size();
03775     for (std::size_t i = 0; i < functions; ++i) {
03776         const Scope * scope = symbolDatabase->functionScopes[i];
03777         // check all the code in the function
03778         for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03779             if (Token::Match(tok, "%var% <|<= 0") && tok->varId() && !Token::Match(tok->previous(), "++|--|)|+|-|*|/|~|<<|>>") && !Token::Match(tok->tokAt(3), "+|-")) {
03780                 const Variable *var = tok->variable();
03781                 if (var && var->typeEndToken()->isUnsigned())
03782                     unsignedLessThanZeroError(tok, var->name(), inconclusive);
03783                 else if (var && var->isPointer() && tok->strAt(-1) != "*")
03784                     pointerLessThanZeroError(tok, inconclusive);
03785             } else if (Token::Match(tok, "0 >|>= %var%") && tok->tokAt(2)->varId() && !Token::Match(tok->tokAt(3), "+|-|*|/") && !Token::Match(tok->previous(), "+|-|<<|>>|~")) {
03786                 const Variable *var = tok->tokAt(2)->variable();
03787                 if (var && var->typeEndToken()->isUnsigned())
03788                     unsignedLessThanZeroError(tok, var->name(), inconclusive);
03789                 else if (var && var->isPointer() && !Token::Match(tok->tokAt(3), "[.[]"))
03790                     pointerLessThanZeroError(tok, inconclusive);
03791             } else if (Token::Match(tok, "0 <= %var%") && tok->tokAt(2)->varId() && !Token::Match(tok->tokAt(3), "+|-|*|/") && !Token::Match(tok->previous(), "+|-|<<|>>|~")) {
03792                 const Variable *var = tok->tokAt(2)->variable();
03793                 if (var && var->typeEndToken()->isUnsigned())
03794                     unsignedPositiveError(tok, var->name(), inconclusive);
03795                 else if (var && var->isPointer() && !Token::Match(tok->tokAt(3), "[.[]"))
03796                     pointerPositiveError(tok, inconclusive);
03797             } else if (Token::Match(tok, "%var% >= 0") && tok->varId() && !Token::Match(tok->previous(), "++|--|)|+|-|*|/|~|<<|>>") && !Token::Match(tok->tokAt(3), "+|-")) {
03798                 const Variable *var = tok->variable();
03799                 if (var && var->typeEndToken()->isUnsigned())
03800                     unsignedPositiveError(tok, var->name(), inconclusive);
03801                 else if (var && var->isPointer() && tok->strAt(-1) != "*")
03802                     pointerPositiveError(tok, inconclusive);
03803             }
03804         }
03805     }
03806 }
03807 
03808 void CheckOther::unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive)
03809 {
03810     if (inconclusive) {
03811         reportError(tok, Severity::style, "unsignedLessThanZero",
03812                     "Checking if unsigned variable '" + varname + "' is less than zero. This might be a false warning.\n"
03813                     "Checking if unsigned variable '" + varname + "' is less than zero. An unsigned "
03814                     "variable will never be negative so it is either pointless or an error to check if it is. "
03815                     "It's not known if the used constant is a template parameter or not and therefore "
03816                     "this message might be a false warning.", true);
03817     } else {
03818         reportError(tok, Severity::style, "unsignedLessThanZero",
03819                     "Checking if unsigned variable '" + varname + "' is less than zero.\n"
03820                     "The unsigned variable '" + varname + "' will never be negative so it "
03821                     "is either pointless or an error to check if it is.");
03822     }
03823 }
03824 
03825 void CheckOther::pointerLessThanZeroError(const Token *tok, bool inconclusive)
03826 {
03827     reportError(tok, Severity::style, "pointerLessThanZero",
03828                 "A pointer can not be negative so it is either pointless or an error to check if it is.", inconclusive);
03829 }
03830 
03831 void CheckOther::unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive)
03832 {
03833     if (inconclusive) {
03834         reportError(tok, Severity::style, "unsignedPositive",
03835                     "Unsigned variable '" + varname + "' can't be negative so it is unnecessary to test it.\n"
03836                     "The unsigned variable '" + varname + "' can't be negative so it is unnecessary to test it. "
03837                     "It's not known if the used constant is a "
03838                     "template parameter or not and therefore this message might be a false warning", true);
03839     } else {
03840         reportError(tok, Severity::style, "unsignedPositive",
03841                     "Unsigned variable '" + varname + "' can't be negative so it is unnecessary to test it.");
03842     }
03843 }
03844 
03845 void CheckOther::pointerPositiveError(const Token *tok, bool inconclusive)
03846 {
03847     reportError(tok, Severity::style, "pointerPositive",
03848                 "A pointer can not be negative so it is either pointless or an error to check if it is not.", inconclusive);
03849 }
03850 
03851 /*
03852 This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &".
03853 In most scenarios, "const A & a = getA()" will be more efficient.
03854 */
03855 void CheckOther::checkRedundantCopy()
03856 {
03857     if (!_settings->isEnabled("performance") || _tokenizer->isC())
03858         return;
03859 
03860     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03861 
03862     for (std::size_t i = 0; i < symbolDatabase->getVariableListSize(); i++) {
03863         const Variable* var = symbolDatabase->getVariableFromVarId(i);
03864 
03865         if (!var || var->isReference() || !var->isConst() || var->isPointer() || !var->type()) // bailout if var is of standard type, if it is a pointer or non-const
03866             continue;
03867 
03868         const Token* startTok = var->nameToken();
03869         const Token* endToken;
03870         if (startTok->strAt(1) == "=") // %type% %var% = ... ;
03871             endToken = Token::findsimplematch(startTok->tokAt(2), ";");
03872         else if (startTok->strAt(1) == "(") // %type% %var%(...)
03873             endToken = startTok->linkAt(1);
03874         else
03875             continue;
03876 
03877         const Token* tok = startTok->tokAt(2);
03878         while (tok && Token::Match(tok, "%var% .|::"))
03879             tok = tok->tokAt(2);
03880         if (!Token::Match(tok, "%var% ("))
03881             continue;
03882         if (tok->linkAt(1)->next() != endToken) // bailout for usage like "const A a = getA()+3"
03883             continue;
03884 
03885         const Function* func = tok->function();
03886         if (func && func->tokenDef->strAt(-1) == "&") {
03887             redundantCopyError(startTok, startTok->str());
03888         }
03889     }
03890 }
03891 void CheckOther::redundantCopyError(const Token *tok,const std::string& varname)
03892 {
03893     reportError(tok, Severity::performance, "redundantCopyLocalConst",
03894                 "Use const reference for '" + varname + "' to avoid unnecessary data copying.\n"
03895                 "The const variable '"+varname+"' is assigned a copy of the data. You can avoid "
03896                 "the unnecessary data copying by converting '" + varname + "' to const reference.");
03897 }
03898 
03899 //---------------------------------------------------------------------------
03900 // Checking for shift by negative values
03901 //---------------------------------------------------------------------------
03902 
03903 void CheckOther::checkNegativeBitwiseShift()
03904 {
03905     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03906 
03907     const std::size_t functions = symbolDatabase->functionScopes.size();
03908     for (std::size_t i = 0; i < functions; ++i) {
03909         const Scope * scope = symbolDatabase->functionScopes[i];
03910         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03911 
03912             if ((Token::Match(tok,"%var% >>|<< %num%") || Token::Match(tok,"%num% >>|<< %num%")) && !Token::Match(tok->previous(),">>|<<")) {
03913                 if (tok->isName()) {
03914                     const Variable *var = tok->variable();
03915                     if (var && var->typeStartToken()->isStandardType() && (tok->strAt(2))[0] == '-')
03916                         negativeBitwiseShiftError(tok);
03917                 } else {
03918                     if ((tok->strAt(2))[0] == '-')
03919                         negativeBitwiseShiftError(tok);
03920                 }
03921             }
03922         }
03923     }
03924 }
03925 
03926 
03927 void CheckOther::negativeBitwiseShiftError(const Token *tok)
03928 {
03929     reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value.");
03930 }
03931 
03932 
03933 //---------------------------------------------------------------------------
03934 // Check for incompletely filled buffers.
03935 //---------------------------------------------------------------------------
03936 void CheckOther::checkIncompleteArrayFill()
03937 {
03938     bool warning = _settings->isEnabled("warning");
03939     bool portability = _settings->isEnabled("portability");
03940     if (!_settings->inconclusive || (!portability && !warning))
03941         return;
03942 
03943     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03944 
03945     const std::size_t functions = symbolDatabase->functionScopes.size();
03946     for (std::size_t i = 0; i < functions; ++i) {
03947         const Scope * scope = symbolDatabase->functionScopes[i];
03948         for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
03949             if (Token::Match(tok, "memset|memcpy|memmove ( %var% ,") && Token::Match(tok->linkAt(1)->tokAt(-2), ", %num% )")) {
03950                 const Variable *var = tok->tokAt(2)->variable();
03951                 if (!var || !var->isArray() || var->dimensions().empty() || !var->dimension(0))
03952                     continue;
03953 
03954                 if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) {
03955                     unsigned int size = _tokenizer->sizeOfType(var->typeStartToken());
03956                     if ((size != 1 && size != 100 && size != 0) || var->typeEndToken()->str() == "*") {
03957                         if (warning)
03958                             incompleteArrayFillError(tok, var->name(), tok->str(), false);
03959                     } else if (var->typeStartToken()->str() == "bool" && portability) // sizeof(bool) is not 1 on all platforms
03960                         incompleteArrayFillError(tok, var->name(), tok->str(), true);
03961                 }
03962             }
03963         }
03964     }
03965 }
03966 
03967 void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean)
03968 {
03969     if (boolean)
03970         reportError(tok, Severity::portability, "incompleteArrayFill",
03971                     "Array '" + buffer + "' might be filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
03972                     "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 + ")'?", true);
03973     else
03974         reportError(tok, Severity::warning, "incompleteArrayFill",
03975                     "Array '" + buffer + "' is filled incompletely. Did you forget to multiply the size given to '" + function + "()' with 'sizeof(*" + buffer + ")'?\n"
03976                     "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 + ")'?", true);
03977 }
03978 
03979 
03980 void CheckOther::oppositeInnerCondition()
03981 {
03982     // FIXME: This check is experimental because of #4170 and #4186. Fix those tickets and remove the "experimental".
03983     if (!_settings->isEnabled("warning") || !_settings->inconclusive || !_settings->experimental)
03984         return;
03985 
03986     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
03987 
03988     for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
03989         const Token* const toke = scope->classDef;
03990 
03991 
03992         if (scope->type == Scope::eIf && toke) {
03993 
03994             const Token *op1Tok, *op2Tok;
03995             op1Tok = scope->classDef->tokAt(2);
03996             op2Tok = scope->classDef->tokAt(4);
03997 
03998             if (scope->classDef->strAt(6) == "{") {
03999 
04000                 const char *oppositeCondition = NULL;
04001 
04002                 if (scope->classDef->strAt(3) == "==")
04003                     oppositeCondition = "if ( %any% !=|<|>|<=|>= %any% )";
04004                 else if (scope->classDef->strAt(3) == "!=")
04005                     oppositeCondition = "if ( %any% ==|>=|<= %any% )";
04006                 else if (scope->classDef->strAt(3) == "<")
04007                     oppositeCondition = "if ( %any% >|>=|== %any% )";
04008                 else if (scope->classDef->strAt(3) == "<=")
04009                     oppositeCondition = "if ( %any% > %any% )";
04010                 else if (scope->classDef->strAt(3) == ">")
04011                     oppositeCondition = "if ( %any% <|<=|== %any% )";
04012                 else if (scope->classDef->strAt(3) == ">=")
04013                     oppositeCondition = "if ( %any% < %any% )";
04014 
04015                 if (oppositeCondition) {
04016                     int flag = 0;
04017 
04018                     for (const Token* tok = scope->classStart; tok != scope->classEnd && flag == 0; tok = tok->next()) {
04019                         if ((tok->str() == op1Tok->str() || tok->str() == op2Tok->str()) && tok->strAt(1) == "=")
04020                             break;
04021                         else if (Token::Match(tok, "%any% ( %any% )")) {
04022                             if ((tok->strAt(2) == op1Tok->str() || tok->strAt(2) == op2Tok->str()))
04023                                 break;
04024                         } else if (Token::Match(tok, "%any% ( %any% , %any%")) {
04025                             for (const Token* tok2 = tok->next(); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
04026                                 if (tok2->str() == op1Tok->str()) {
04027                                     flag = 1;
04028                                     break;
04029                                 }
04030                             }
04031                         } else if (Token::Match(tok, oppositeCondition)) {
04032                             if ((tok->strAt(2) == op1Tok->str() && tok->strAt(4) == op2Tok->str()) || (tok->strAt(2) == op2Tok->str() && tok->strAt(4) == op1Tok->str()))
04033                                 oppositeInnerConditionError(toke);
04034                         }
04035                     }
04036                 }
04037             }
04038         }
04039     }
04040 }
04041 
04042 void CheckOther::oppositeInnerConditionError(const Token *tok)
04043 {
04044     reportError(tok, Severity::warning, "oppositeInnerCondition", "Opposite conditions in nested 'if' blocks lead to a dead code block.", true);
04045 }
04046 
04047 
04048 void CheckOther::checkVarFuncNullUB()
04049 {
04050     if (!_settings->isEnabled("portability"))
04051         return;
04052 
04053     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
04054     const std::size_t functions = symbolDatabase->functionScopes.size();
04055     for (std::size_t i = 0; i < functions; ++i) {
04056         const Scope * scope = symbolDatabase->functionScopes[i];
04057         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
04058             // Is NULL passed to a function?
04059             if (Token::Match(tok,"[(,] NULL [,)]")) {
04060                 // Locate function name in this function call.
04061                 const Token *ftok = tok;
04062                 std::size_t argnr = 1;
04063                 while (ftok && ftok->str() != "(") {
04064                     if (ftok->str() == ")")
04065                         ftok = ftok->link();
04066                     else if (ftok->str() == ",")
04067                         ++argnr;
04068                     ftok = ftok->previous();
04069                 }
04070                 ftok = ftok ? ftok->previous() : NULL;
04071                 if (ftok && ftok->isName()) {
04072                     // If this is a variadic function then report error
04073                     const Function *f = ftok->function();
04074                     if (f && f->argCount() <= argnr) {
04075                         const Token *tok2 = f->argDef;
04076                         tok2 = tok2 ? tok2->link() : NULL; // goto ')'
04077                         if (Token::simpleMatch(tok2->tokAt(-3), ". . ."))
04078                             varFuncNullUBError(tok);
04079                     }
04080                 }
04081             }
04082         }
04083     }
04084 }
04085 
04086 void CheckOther::varFuncNullUBError(const Token *tok)
04087 {
04088     reportError(tok,
04089                 Severity::portability,
04090                 "varFuncNullUB",
04091                 "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
04092                 "Passing NULL after the last typed argument to a variadic function leads to undefined behaviour.\n"
04093                 "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"
04094                 "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"
04095                 "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"
04096                 "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"
04097                 "#include <stdarg.h>\n"
04098                 "#include <stdio.h>\n"
04099                 "\n"
04100                 "void f(char *s, ...) {\n"
04101                 "    va_list ap;\n"
04102                 "    va_start(ap,s);\n"
04103                 "    for (;;) {\n"
04104                 "        char *p = va_arg(ap,char*);\n"
04105                 "        printf(\"%018p, %s\n\", p, (long)p & 255 ? p : \"\");\n"
04106                 "        if(!p) break;\n"
04107                 "    }\n"
04108                 "    va_end(ap);\n"
04109                 "}\n"
04110                 "\n"
04111                 "void g() {\n"
04112                 "    char *s2 = \"x\";\n"
04113                 "    char *s3 = \"ERROR\";\n"
04114                 "\n"
04115                 "    // changing 0 to 0L for the 7th argument (which is intended to act as sentinel) makes the error go away on x86_64\n"
04116                 "    f(\"first\", s2, s2, s2, s2, s2, 0, s3, (char*)0);\n"
04117                 "}\n"
04118                 "\n"
04119                 "void h() {\n"
04120                 "    int i;\n"
04121                 "    volatile unsigned char a[1000];\n"
04122                 "    for (i = 0; i<sizeof(a); i++)\n"
04123                 "        a[i] = -1;\n"
04124                 "}\n"
04125                 "\n"
04126                 "int main() {\n"
04127                 "    h();\n"
04128                 "    g();\n"
04129                 "    return 0;\n"
04130                 "}");
04131 }