LCOV - code coverage report
Current view: top level - lib - checkio.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 450 459 98.0 %
Date: 2013-03-30 Functions: 28 28 100.0 %
Branches: 991 1550 63.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Cppcheck - A tool for static C/C++ code analysis
       3                 :            :  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
       4                 :            :  *
       5                 :            :  * This program is free software: you can redistribute it and/or modify
       6                 :            :  * it under the terms of the GNU General Public License as published by
       7                 :            :  * the Free Software Foundation, either version 3 of the License, or
       8                 :            :  * (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This program is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13                 :            :  * GNU General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU General Public License
      16                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17                 :            :  */
      18                 :            : 
      19                 :            : //---------------------------------------------------------------------------
      20                 :            : #include "checkio.h"
      21                 :            : 
      22                 :            : #include "tokenize.h"
      23                 :            : #include "token.h"
      24                 :            : #include "errorlogger.h"
      25                 :            : #include "symboldatabase.h"
      26                 :            : 
      27                 :            : #include <cctype>
      28                 :            : #include <cstdlib>
      29                 :            : 
      30                 :            : //---------------------------------------------------------------------------
      31                 :            : 
      32                 :            : // Register CheckIO..
      33                 :            : namespace {
      34                 :         45 :     CheckIO instance;
      35                 :            : }
      36                 :            : 
      37                 :            : 
      38                 :            : //---------------------------------------------------------------------------
      39                 :            : //    std::cout << std::cout;
      40                 :            : //---------------------------------------------------------------------------
      41                 :       3796 : void CheckIO::checkCoutCerrMisusage()
      42                 :            : {
      43                 :       3796 :     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
      44                 :       3796 :     std::size_t functions = symbolDatabase->functionScopes.size();
      45         [ +  + ]:       7682 :     for (std::size_t i = 0; i < functions; ++i) {
      46                 :       3886 :         const Scope * scope = symbolDatabase->functionScopes[i];
      47                 :       3886 :         bool firstCout = false;
      48 [ +  - ][ +  + ]:      72728 :         for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
                 [ +  + ]
      49         [ +  + ]:      68842 :             if (tok->str() == "(")
      50                 :      12411 :                 tok = tok->link();
      51                 :            : 
      52         [ +  + ]:      68842 :             if (Token::Match(tok, "std :: cout|cerr")) {
      53 [ +  + ][ +  - ]:        450 :                 if (firstCout && tok->strAt(-1) == "<<" && tok->strAt(3) != ".") {
         [ +  + ][ +  + ]
      54                 :        135 :                     coutCerrMisusageError(tok, tok->strAt(2));
      55                 :        135 :                     firstCout = false;
      56         [ +  + ]:        315 :                 } else if (tok->strAt(3) == "<<")
      57                 :        270 :                     firstCout = true;
      58 [ +  + ][ +  + ]:      68392 :             } else if (firstCout && tok->str() == ";")
                 [ +  + ]
      59                 :        135 :                 firstCout = false;
      60                 :            :         }
      61                 :            :     }
      62                 :       3796 : }
      63                 :            : 
      64                 :        180 : void CheckIO::coutCerrMisusageError(const Token* tok, const std::string& streamName)
      65                 :            : {
      66 [ +  - ][ +  - ]:        180 :     reportError(tok, Severity::error, "coutCerrMisusage", "Invalid usage of output stream: '<< std::" + streamName + "'.");
         [ +  - ][ +  - ]
                 [ +  - ]
      67                 :        180 : }
      68                 :            : 
      69                 :            : //---------------------------------------------------------------------------
      70                 :            : // fflush(stdin) <- fflush only applies to output streams in ANSI C
      71                 :            : // fread(); fwrite(); <- consecutive read/write statements require repositioning in between
      72                 :            : // fopen("","r"); fwrite(); <- write to read-only file (or vice versa)
      73                 :            : // fclose(); fread(); <- Use closed file
      74                 :            : //---------------------------------------------------------------------------
      75                 :            : enum OpenMode {CLOSED, READ_MODE, WRITE_MODE, RW_MODE, UNKNOWN};
      76                 :        990 : static OpenMode getMode(const std::string& str)
      77                 :            : {
      78         [ +  + ]:        990 :     if (str.find('+', 1) != std::string::npos)
      79                 :        135 :         return RW_MODE;
      80 [ +  + ][ +  + ]:        855 :     else if (str.find('w') != std::string::npos || str.find('a') != std::string::npos)
                 [ +  + ]
      81                 :        360 :         return WRITE_MODE;
      82         [ +  + ]:        495 :     else if (str.find('r') != std::string::npos)
      83                 :        360 :         return READ_MODE;
      84                 :        990 :     return UNKNOWN;
      85                 :            : }
      86                 :            : 
      87                 :            : struct Filepointer {
      88                 :            :     OpenMode mode;
      89                 :            :     unsigned int mode_indent;
      90                 :            :     enum Operation {NONE, UNIMPORTANT, READ, WRITE, POSITIONING, OPEN, CLOSE, UNKNOWN_OP} lastOperation;
      91                 :            :     unsigned int op_indent;
      92                 :       1755 :     Filepointer(OpenMode mode_ = UNKNOWN)
      93                 :       1755 :         : mode(mode_), mode_indent(0), lastOperation(NONE), op_indent(0) {
      94                 :       1755 :     }
      95                 :            : };
      96                 :            : 
      97                 :       3796 : void CheckIO::checkFileUsage()
      98                 :            : {
      99                 :            :     static const char* _whitelist[] = {
     100                 :            :         "clearerr", "feof", "ferror", "fgetpos", "ftell", "setbuf", "setvbuf", "ungetc"
     101                 :            :     };
     102 [ +  + ][ +  - ]:       3796 :     static const std::set<std::string> whitelist(_whitelist, _whitelist + sizeof(_whitelist)/sizeof(*_whitelist));
         [ +  - ][ #  # ]
     103                 :            : 
     104                 :       3796 :     std::map<unsigned int, Filepointer> filepointers;
     105                 :            : 
     106                 :       3796 :     const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
     107         [ +  - ]:       3796 :     std::size_t varListSize = symbolDatabase->getVariableListSize();
     108         [ +  + ]:      10987 :     for (std::size_t i = 1; i < varListSize; ++i) {
     109         [ +  - ]:       7191 :         const Variable* var = symbolDatabase->getVariableFromVarId(i);
     110 [ +  + ][ +  - ]:       7191 :         if (!var || !var->varId() || var->isArray() || !Token::simpleMatch(var->typeStartToken(), "FILE *"))
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
     111                 :       5571 :             continue;
     112                 :            : 
     113 [ +  - ][ +  + ]:       1620 :         if (var->isLocal()) {
     114 [ +  - ][ +  - ]:        270 :             if (var->nameToken()->strAt(1) == "(") // initialize by calling "ctor"
                 [ +  + ]
     115 [ +  - ][ +  - ]:         45 :                 filepointers.insert(std::make_pair(var->varId(), Filepointer(UNKNOWN)));
     116                 :            :             else
     117 [ +  - ][ +  - ]:        225 :                 filepointers.insert(std::make_pair(var->varId(), Filepointer(CLOSED)));
     118                 :            :         } else {
     119 [ +  - ][ +  - ]:       1350 :             filepointers.insert(std::make_pair(var->varId(), Filepointer(UNKNOWN)));
     120                 :            :             // TODO: If all fopen calls we find open the file in the same type, we can set Filepointer::mode
     121                 :            :         }
     122                 :            :     }
     123                 :            : 
     124                 :       3796 :     std::size_t functions = symbolDatabase->functionScopes.size();
     125         [ +  + ]:       7682 :     for (std::size_t j = 0; j < functions; ++j) {
     126                 :       3886 :         const Scope * scope = symbolDatabase->functionScopes[j];
     127                 :       3886 :         unsigned int indent = 0;
     128         [ +  + ]:     131750 :         for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
     129 [ +  - ][ +  + ]:     127864 :             if (tok->str() == "{")
     130                 :       6217 :                 indent++;
     131 [ +  - ][ +  + ]:     121647 :             else if (tok->str() == "}") {
     132                 :       2331 :                 indent--;
     133 [ +  - ][ +  - ]:       3096 :                 for (std::map<unsigned int, Filepointer>::iterator i = filepointers.begin(); i != filepointers.end(); ++i) {
                 [ +  + ]
     134 [ +  - ][ +  + ]:        765 :                     if (indent < i->second.mode_indent) {
     135         [ +  - ]:        180 :                         i->second.mode_indent = 0;
     136         [ +  - ]:        180 :                         i->second.mode = UNKNOWN;
     137                 :            :                     }
     138 [ +  - ][ +  + ]:        765 :                     if (indent < i->second.op_indent) {
     139         [ +  - ]:        540 :                         i->second.op_indent = 0;
     140         [ +  - ]:        540 :                         i->second.lastOperation = Filepointer::UNKNOWN_OP;
     141                 :            :                     }
     142                 :            :                 }
     143 [ +  - ][ +  + ]:     119316 :             } else if (tok->str() == "return" || tok->str() == "continue" || tok->str() == "break") { // Reset upon return, continue or break
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
                 [ +  + ]
     144 [ +  - ][ +  - ]:        480 :                 for (std::map<unsigned int, Filepointer>::iterator i = filepointers.begin(); i != filepointers.end(); ++i) {
                 [ +  + ]
     145         [ +  - ]:        225 :                     i->second.mode_indent = 0;
     146         [ +  - ]:        225 :                     i->second.mode = UNKNOWN;
     147         [ +  - ]:        225 :                     i->second.op_indent = 0;
     148         [ +  - ]:        225 :                     i->second.lastOperation = Filepointer::UNKNOWN_OP;
     149                 :            :                 }
     150 [ +  + ][ +  - ]:     119061 :             } else if (tok->varId() && Token::Match(tok, "%var% =") && (tok->strAt(2) != "fopen" && tok->strAt(2) != "freopen" && tok->strAt(2) != "tmpfile")) {
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  + ]
     151         [ +  - ]:       1791 :                 std::map<unsigned int, Filepointer>::iterator i = filepointers.find(tok->varId());
     152 [ +  - ][ +  + ]:       1791 :                 if (i != filepointers.end()) {
     153         [ +  - ]:         45 :                     i->second.mode = UNKNOWN;
     154         [ +  - ]:         45 :                     i->second.lastOperation = Filepointer::UNKNOWN_OP;
     155                 :            :                 }
     156 [ +  - ][ +  + ]:     117270 :             } else if (Token::Match(tok, "%var% (") && tok->previous() && (!tok->previous()->isName() || Token::Match(tok->previous(), "return|throw"))) {
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
                 [ +  + ]
     157         [ +  - ]:      12906 :                 std::string mode;
     158                 :      12906 :                 const Token* fileTok = 0;
     159                 :      12906 :                 Filepointer::Operation operation = Filepointer::NONE;
     160                 :            : 
     161 [ +  - ][ +  + ]:      12906 :                 if ((tok->str() == "fopen" || tok->str() == "freopen" || tok->str() == "tmpfile") && tok->strAt(-1) == "=") {
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
     162 [ +  - ][ +  - ]:       1035 :                     if (tok->str() != "tmpfile") {
     163 [ +  - ][ +  - ]:       1035 :                         const Token* modeTok = tok->tokAt(2)->nextArgument();
     164 [ +  - ][ +  + ]:       1035 :                         if (modeTok && modeTok->type() == Token::eString)
                 [ +  + ]
     165 [ +  - ][ +  - ]:        855 :                             mode = modeTok->strValue();
                 [ +  - ]
     166                 :            :                     } else
     167         [ #  # ]:          0 :                         mode = "wb+";
     168         [ +  - ]:       1035 :                     fileTok = tok->tokAt(-2);
     169                 :       1035 :                     operation = Filepointer::OPEN;
     170 [ +  - ][ +  + ]:      11871 :                 } else if (tok->str() == "rewind" || tok->str() == "fseek" || tok->str() == "fsetpos" || tok->str() == "fflush") {
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
                 [ +  + ]
     171 [ +  - ][ +  + ]:        405 :                     if (Token::simpleMatch(tok, "fflush ( stdin )"))
     172 [ +  - ][ +  - ]:         45 :                         fflushOnInputStreamError(tok, tok->strAt(2));
     173                 :            :                     else {
     174         [ +  - ]:        360 :                         fileTok = tok->tokAt(2);
     175                 :        360 :                         operation = Filepointer::POSITIONING;
     176                 :            :                     }
     177 [ +  - ][ +  - ]:      11466 :                 } else if (tok->str() == "fgetc" || tok->str() == "fgets" || tok->str() == "fread" || tok->str() == "fscanf" || tok->str() == "getc") {
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
                 [ +  + ]
     178 [ +  - ][ +  + ]:       1035 :                     if (tok->str() == "fscanf")
     179         [ +  - ]:        135 :                         fileTok = tok->tokAt(2);
     180                 :            :                     else
     181         [ +  - ]:        900 :                         fileTok = tok->linkAt(1)->previous();
     182                 :       1035 :                     operation = Filepointer::READ;
     183 [ +  - ][ +  - ]:      10431 :                 } else if (tok->str() == "fputc" || tok->str() == "fputs" || tok->str() == "fwrite" || tok->str() == "fprintf" || tok->str() == "putcc") {
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
                 [ +  + ]
     184 [ +  - ][ +  + ]:       1395 :                     if (tok->str() == "fprintf")
     185         [ +  - ]:        270 :                         fileTok = tok->tokAt(2);
     186                 :            :                     else
     187         [ +  - ]:       1125 :                         fileTok = tok->linkAt(1)->previous();
     188                 :       1395 :                     operation = Filepointer::WRITE;
     189 [ +  - ][ +  + ]:       9036 :                 } else if (tok->str() == "fclose") {
     190         [ +  - ]:        585 :                     fileTok = tok->tokAt(2);
     191                 :        585 :                     operation = Filepointer::CLOSE;
     192 [ +  - ][ +  - ]:       8451 :                 } else if (whitelist.find(tok->str()) != whitelist.end()) {
                 [ +  + ]
     193         [ +  - ]:        225 :                     fileTok = tok->tokAt(2);
     194 [ +  - ][ +  + ]:        225 :                     if (tok->str() == "ungetc" && fileTok)
         [ +  - ][ +  + ]
     195         [ +  - ]:         45 :                         fileTok = fileTok->nextArgument();
     196                 :        225 :                     operation = Filepointer::UNIMPORTANT;
     197 [ +  - ][ +  + ]:       8226 :                 } else if (!Token::Match(tok, "if|for|while|catch|switch")) {
     198         [ +  - ]:       7821 :                     const Token* const end2 = tok->linkAt(1);
     199 [ +  - ][ +  + ]:      32472 :                     for (const Token* tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
     200 [ +  + ][ +  - ]:      24651 :                         if (tok2->varId() && filepointers.find(tok2->varId()) != filepointers.end()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     201                 :         45 :                             fileTok = tok2;
     202                 :         45 :                             operation = Filepointer::UNKNOWN_OP; // Assume that repositioning was last operation and that the file is opened now
     203                 :         45 :                             break;
     204                 :            :                         }
     205                 :            :                     }
     206                 :            :                 }
     207                 :            : 
     208 [ +  - ][ +  + ]:      12996 :                 while (Token::Match(fileTok, "%var% ."))
     209         [ +  - ]:         90 :                     fileTok = fileTok->tokAt(2);
     210                 :            : 
     211 [ +  + ][ +  + ]:      12906 :                 if (!fileTok || !fileTok->varId())
                 [ +  + ]
     212                 :       8586 :                     continue;
     213                 :            : 
     214 [ +  - ][ +  - ]:       4320 :                 if (filepointers.find(fileTok->varId()) == filepointers.end()) { // function call indicates: Its a File
                 [ +  + ]
     215 [ +  - ][ +  - ]:        135 :                     filepointers.insert(std::make_pair(fileTok->varId(), Filepointer(UNKNOWN)));
     216                 :            :                 }
     217         [ +  - ]:       4320 :                 Filepointer& f = filepointers[fileTok->varId()];
     218                 :            : 
     219   [ +  +  +  +  :       4320 :                 switch (operation) {
             +  +  +  - ]
     220                 :            :                 case Filepointer::OPEN:
     221         [ +  - ]:        990 :                     f.mode = getMode(mode);
     222                 :        990 :                     f.mode_indent = indent;
     223                 :        990 :                     break;
     224                 :            :                 case Filepointer::POSITIONING:
     225         [ -  + ]:        315 :                     if (f.mode == CLOSED)
     226         [ #  # ]:          0 :                         useClosedFileError(tok);
     227                 :        315 :                     break;
     228                 :            :                 case Filepointer::READ:
     229         [ +  + ]:        945 :                     if (f.mode == CLOSED)
     230         [ +  - ]:         45 :                         useClosedFileError(tok);
     231         [ +  + ]:        900 :                     else if (f.mode == WRITE_MODE)
     232         [ +  - ]:        180 :                         readWriteOnlyFileError(tok);
     233         [ +  + ]:        720 :                     else if (f.lastOperation == Filepointer::WRITE)
     234         [ +  - ]:         45 :                         ioWithoutPositioningError(tok);
     235                 :        945 :                     break;
     236                 :            :                 case Filepointer::WRITE:
     237         [ +  + ]:       1215 :                     if (f.mode == CLOSED)
     238         [ +  - ]:        135 :                         useClosedFileError(tok);
     239         [ +  + ]:       1080 :                     else if (f.mode == READ_MODE)
     240         [ +  - ]:        135 :                         writeReadOnlyFileError(tok);
     241         [ +  + ]:        945 :                     else if (f.lastOperation == Filepointer::READ)
     242         [ +  - ]:         90 :                         ioWithoutPositioningError(tok);
     243                 :       1215 :                     break;
     244                 :            :                 case Filepointer::CLOSE:
     245         [ -  + ]:        585 :                     if (f.mode == CLOSED)
     246         [ #  # ]:          0 :                         useClosedFileError(tok);
     247                 :            :                     else
     248                 :        585 :                         f.mode = CLOSED;
     249                 :        585 :                     f.mode_indent = indent;
     250                 :        585 :                     break;
     251                 :            :                 case Filepointer::UNIMPORTANT:
     252         [ +  + ]:        225 :                     if (f.mode == CLOSED)
     253         [ +  - ]:         90 :                         useClosedFileError(tok);
     254                 :        225 :                     break;
     255                 :            :                 case Filepointer::UNKNOWN_OP:
     256                 :         45 :                     f.mode = UNKNOWN;
     257                 :         45 :                     f.mode_indent = 0;
     258                 :         45 :                     break;
     259                 :            :                 default:
     260                 :          0 :                     break;
     261                 :            :                 }
     262 [ +  - ][ +  + ]:       4320 :                 if (operation != Filepointer::NONE && operation != Filepointer::UNIMPORTANT) {
     263                 :       4095 :                     f.op_indent = indent;
     264                 :       4320 :                     f.lastOperation = operation;
     265         [ +  - ]:      12906 :                 }
     266                 :            :             }
     267                 :            :         }
     268 [ +  - ][ +  - ]:       5686 :         for (std::map<unsigned int, Filepointer>::iterator i = filepointers.begin(); i != filepointers.end(); ++i) {
                 [ +  + ]
     269         [ +  - ]:       1800 :             i->second.op_indent = 0;
     270         [ +  - ]:       1800 :             i->second.mode = UNKNOWN;
     271         [ +  - ]:       1800 :             i->second.lastOperation = Filepointer::UNKNOWN_OP;
     272                 :            :         }
     273                 :       3796 :     }
     274                 :       3796 : }
     275                 :            : 
     276                 :         90 : void CheckIO::fflushOnInputStreamError(const Token *tok, const std::string &varname)
     277                 :            : {
     278                 :            :     reportError(tok, Severity::error,
     279 [ +  - ][ +  - ]:         90 :                 "fflushOnInputStream", "fflush() called on input stream '" + varname + "' results in undefined behaviour.");
         [ +  - ][ +  - ]
                 [ +  - ]
     280                 :         90 : }
     281                 :            : 
     282                 :        180 : void CheckIO::ioWithoutPositioningError(const Token *tok)
     283                 :            : {
     284                 :            :     reportError(tok, Severity::error,
     285 [ +  - ][ +  - ]:        180 :                 "IOWithoutPositioning", "Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour.");
         [ +  - ][ +  - ]
                 [ +  - ]
     286                 :        180 : }
     287                 :            : 
     288                 :        225 : void CheckIO::readWriteOnlyFileError(const Token *tok)
     289                 :            : {
     290                 :            : 
     291                 :            :     reportError(tok, Severity::error,
     292 [ +  - ][ +  - ]:        225 :                 "readWriteOnlyFile", "Read operation on a file that was opened only for writing.");
         [ +  - ][ +  - ]
                 [ +  - ]
     293                 :        225 : }
     294                 :            : 
     295                 :        180 : void CheckIO::writeReadOnlyFileError(const Token *tok)
     296                 :            : {
     297                 :            :     reportError(tok, Severity::error,
     298 [ +  - ][ +  - ]:        180 :                 "writeReadOnlyFile", "Write operation on a file that was opened only for reading.");
         [ +  - ][ +  - ]
                 [ +  - ]
     299                 :        180 : }
     300                 :            : 
     301                 :        315 : void CheckIO::useClosedFileError(const Token *tok)
     302                 :            : {
     303                 :            :     reportError(tok, Severity::error,
     304 [ +  - ][ +  - ]:        315 :                 "useClosedFile", "Used file that is not opened.");
         [ +  - ][ +  - ]
                 [ +  - ]
     305                 :        315 : }
     306                 :            : 
     307                 :            : 
     308                 :            : //---------------------------------------------------------------------------
     309                 :            : // scanf without field width limits can crash with huge input data
     310                 :            : //---------------------------------------------------------------------------
     311                 :       3796 : void CheckIO::invalidScanf()
     312                 :            : {
     313 [ +  - ][ +  - ]:       3796 :     if (!_settings->isEnabled("warning") && !_settings->isEnabled("portability"))
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     314                 :       3796 :         return;
     315                 :            : 
     316                 :       3060 :     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
     317                 :       3060 :     std::size_t functions = symbolDatabase->functionScopes.size();
     318         [ +  + ]:       6210 :     for (std::size_t j = 0; j < functions; ++j) {
     319                 :       3150 :         const Scope * scope = symbolDatabase->functionScopes[j];
     320         [ +  + ]:     103905 :         for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
     321                 :     100755 :             const Token *formatToken = 0;
     322         [ +  + ]:     100755 :             if (Token::Match(tok, "scanf|vscanf ( %str% ,"))
     323                 :        945 :                 formatToken = tok->tokAt(2);
     324         [ +  + ]:      99810 :             else if (Token::Match(tok, "sscanf|vsscanf|fscanf|vfscanf (")) {
     325                 :        720 :                 const Token* nextArg = tok->tokAt(2)->nextArgument();
     326 [ +  - ][ +  - ]:        720 :                 if (nextArg && nextArg->type() == Token::eString)
                 [ +  - ]
     327                 :        720 :                     formatToken = nextArg;
     328                 :            :                 else
     329                 :          0 :                     continue;
     330                 :            :             } else
     331                 :      99090 :                 continue;
     332                 :            : 
     333                 :       1665 :             bool format = false;
     334                 :            : 
     335                 :            :             // scan the string backwards, so we dont need to keep states
     336                 :       1665 :             const std::string &formatstr(formatToken->str());
     337         [ +  + ]:      11700 :             for (unsigned int i = 1; i < formatstr.length(); i++) {
     338         [ +  + ]:      10035 :                 if (formatstr[i] == '%')
     339                 :       2160 :                     format = !format;
     340                 :            : 
     341         [ +  + ]:       7875 :                 else if (!format)
     342                 :       5805 :                     continue;
     343                 :            : 
     344 [ +  + ][ +  + ]:       2070 :                 else if (std::isdigit(formatstr[i]) || formatstr[i] == '*') {
                 [ +  + ]
     345                 :       1485 :                     format = false;
     346                 :            :                 }
     347                 :            : 
     348 [ +  + ][ +  - ]:        585 :                 else if (std::isalpha(formatstr[i]) || formatstr[i] == '[') {
                 [ +  - ]
     349 [ +  - ][ +  + ]:        585 :                     if ((formatstr[i] == 's' || formatstr[i] == '[' || formatstr[i] == 'S' || (formatstr[i] == 'l' && formatstr[i+1] == 's')) && _settings->isEnabled("warning"))  // #3490 - field width limits are only necessary for string input
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ #  # ]
                 [ #  # ]
     350                 :        270 :                         invalidScanfError(tok, false);
     351 [ +  - ][ +  + ]:        315 :                     else if (formatstr[i] != 'n' && formatstr[i] != 'c' && _settings->platformType != Settings::Win32A && _settings->platformType != Settings::Win32W && _settings->platformType != Settings::Win64 && _settings->isEnabled("portability"))
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
         [ #  # ][ #  # ]
     352                 :         45 :                         invalidScanfError(tok, true); // Warn about libc bug in versions prior to 2.13-25
     353                 :        585 :                     format = false;
     354                 :            :                 }
     355                 :            :             }
     356                 :            :         }
     357                 :            :     }
     358                 :            : }
     359                 :            : 
     360                 :        360 : void CheckIO::invalidScanfError(const Token *tok, bool portability)
     361                 :            : {
     362         [ +  + ]:        360 :     if (portability)
     363                 :            :         reportError(tok, Severity::portability,
     364                 :            :                     "invalidscanf", "scanf without field width limits can crash with huge input data on some versions of libc.\n"
     365                 :            :                     "scanf without field width limits can crash with huge input data on libc versions older than 2.13-25. Add a field "
     366                 :            :                     "width specifier to fix this problem:\n"
     367                 :            :                     "    %i => %3i\n"
     368                 :            :                     "\n"
     369                 :            :                     "Sample program that can crash:\n"
     370                 :            :                     "\n"
     371                 :            :                     "#include <stdio.h>\n"
     372                 :            :                     "int main()\n"
     373                 :            :                     "{\n"
     374                 :            :                     "    int a;\n"
     375                 :            :                     "    scanf(\"%i\", &a);\n"
     376                 :            :                     "    return 0;\n"
     377                 :            :                     "}\n"
     378                 :            :                     "\n"
     379                 :            :                     "To make it crash:\n"
     380 [ +  - ][ +  - ]:         45 :                     "perl -e 'print \"5\"x2100000' | ./a.out");
         [ +  - ][ +  - ]
                 [ +  - ]
     381                 :            :     else
     382                 :            :         reportError(tok, Severity::warning,
     383                 :            :                     "invalidscanf", "scanf without field width limits can crash with huge input data.\n"
     384                 :            :                     "scanf without field width limits can crash with huge input data. Add a field width "
     385                 :            :                     "specifier to fix this problem:\n"
     386                 :            :                     "    %s => %20s\n"
     387                 :            :                     "\n"
     388                 :            :                     "Sample program that can crash:\n"
     389                 :            :                     "\n"
     390                 :            :                     "#include <stdio.h>\n"
     391                 :            :                     "int main()\n"
     392                 :            :                     "{\n"
     393                 :            :                     "    char c[5];\n"
     394                 :            :                     "    scanf(\"%s\", c);\n"
     395                 :            :                     "    return 0;\n"
     396                 :            :                     "}\n"
     397                 :            :                     "\n"
     398 [ +  - ][ +  - ]:        315 :                     "To make it crash, type in more than 5 characters.");
         [ +  - ][ +  - ]
                 [ +  - ]
     399                 :        360 : }
     400                 :            : 
     401                 :            : //---------------------------------------------------------------------------
     402                 :            : //    printf("%u", "xyz"); // Wrong argument type
     403                 :            : //    printf("%u%s", 1); // Too few arguments
     404                 :            : //    printf("", 1); // Too much arguments
     405                 :            : //---------------------------------------------------------------------------
     406                 :        900 : static bool isComplexType(const Variable* var, const Token* varTypeTok)
     407                 :            : {
     408         [ +  + ]:        900 :     if (var->type())
     409                 :        360 :         return(true);
     410                 :            : 
     411 [ +  + ][ +  - ]:        540 :     static std::set<std::string> knownTypes;
         [ +  - ][ #  # ]
     412         [ +  + ]:        540 :     if (knownTypes.empty()) {
     413 [ +  - ][ +  - ]:         45 :         knownTypes.insert("struct"); // If a type starts with the struct keyword, its a complex type
                 [ +  - ]
     414 [ +  - ][ +  - ]:         45 :         knownTypes.insert("string");
                 [ +  - ]
     415 [ +  - ][ +  - ]:         45 :         knownTypes.insert("wstring");
                 [ +  - ]
     416                 :            :     }
     417                 :            : 
     418         [ +  + ]:        540 :     if (varTypeTok->str() == "std")
     419                 :         90 :         varTypeTok = varTypeTok->tokAt(2);
     420 [ +  + ][ -  + ]:        900 :     return((knownTypes.find(varTypeTok->str()) != knownTypes.end() || (varTypeTok->strAt(1) == "<" && varTypeTok->linkAt(1) && varTypeTok->linkAt(1)->strAt(1) != "::")) && !var->isPointer() && !var->isArray());
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
     421                 :            : }
     422                 :            : 
     423                 :       2475 : static bool isKnownType(const Variable* var, const Token* varTypeTok)
     424                 :            : {
     425 [ +  + ][ +  - ]:       2475 :     return(varTypeTok->isStandardType() || varTypeTok->next()->isStandardType() || isComplexType(var, varTypeTok));
                 [ +  + ]
     426                 :            : }
     427                 :            : 
     428                 :       3796 : void CheckIO::checkWrongPrintfScanfArguments()
     429                 :            : {
     430                 :       3796 :     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
     431 [ +  - ][ +  - ]:       3796 :     bool warning = _settings->isEnabled("warning");
                 [ +  - ]
     432                 :            : 
     433                 :       3796 :     std::size_t functions = symbolDatabase->functionScopes.size();
     434         [ +  + ]:       7682 :     for (std::size_t j = 0; j < functions; ++j) {
     435                 :       3886 :         const Scope * scope = symbolDatabase->functionScopes[j];
     436         [ +  + ]:     128689 :         for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
     437         [ +  + ]:     124803 :             if (!tok->isName()) continue;
     438                 :            : 
     439                 :      38469 :             const Token* argListTok = 0; // Points to first va_list argument
     440                 :      38469 :             std::string formatString;
     441                 :            : 
     442 [ +  - ][ +  + ]:      38469 :             if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%")) {
     443 [ +  - ][ +  - ]:       4725 :                 formatString = tok->strAt(2);
     444 [ +  - ][ +  - ]:       4725 :                 if (tok->strAt(3) == ",") {
                 [ +  + ]
     445         [ +  - ]:       4545 :                     argListTok = tok->tokAt(4);
     446 [ +  - ][ +  - ]:        180 :                 } else if (tok->strAt(3) == ")") {
                 [ +  + ]
     447                 :        135 :                     argListTok = 0;
     448                 :            :                 } else {
     449                 :         45 :                     continue;
     450                 :            :                 }
     451 [ +  - ][ +  + ]:      33744 :             } else if (Token::Match(tok, "sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any%")) {
     452 [ +  - ][ +  - ]:       1080 :                 const Token* formatStringTok = tok->tokAt(2)->nextArgument(); // Find second parameter (format string)
     453 [ +  - ][ +  + ]:       1080 :                 if (Token::Match(formatStringTok, "%str% ,")) {
     454         [ +  - ]:        855 :                     argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args)
     455         [ +  - ]:        855 :                     formatString = formatStringTok->str();
     456 [ +  - ][ +  + ]:        225 :                 } else if (Token::Match(formatStringTok, "%str% )")) {
     457                 :        180 :                     argListTok = 0; // Find third parameter (first argument of va_args)
     458         [ +  - ]:        180 :                     formatString = formatStringTok->str();
     459                 :            :                 } else {
     460                 :         45 :                     continue;
     461                 :            :                 }
     462 [ +  - ][ +  + ]:      32664 :             } else if (Token::Match(tok, "snprintf|fnprintf|swprintf (")) {
     463         [ +  - ]:        135 :                 const Token* formatStringTok = tok->tokAt(2);
     464 [ +  + ][ +  - ]:        405 :                 for (int i = 0; i < 2 && formatStringTok; i++) {
                 [ +  + ]
     465         [ +  - ]:        270 :                     formatStringTok = formatStringTok->nextArgument(); // Find third parameter (format string)
     466                 :            :                 }
     467 [ +  - ][ +  + ]:        135 :                 if (Token::Match(formatStringTok, "%str% ,")) {
     468         [ +  - ]:         45 :                     argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args)
     469         [ +  - ]:         45 :                     formatString = formatStringTok->str();
     470 [ +  - ][ +  + ]:         90 :                 } else if (Token::Match(formatStringTok, "%str% )")) {
     471                 :         45 :                     argListTok = 0; // Find fourth parameter (first argument of va_args)
     472         [ +  - ]:         45 :                     formatString = formatStringTok->str();
     473                 :            :                 } else {
     474                 :         45 :                     continue;
     475                 :            :                 }
     476                 :            :             } else {
     477                 :      32529 :                 continue;
     478                 :            :             }
     479                 :            : 
     480                 :            :             // Count format string parameters..
     481         [ +  - ]:       5805 :             bool scan = Token::Match(tok, "sscanf|fscanf|scanf|swscanf|fwscanf|wscanf");
     482                 :       5805 :             unsigned int numFormat = 0;
     483                 :       5805 :             bool percent = false;
     484                 :       5805 :             const Token* argListTok2 = argListTok;
     485 [ +  - ][ +  - ]:      38520 :             for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
         [ +  - ][ +  + ]
     486         [ +  + ]:      32760 :                 if (*i == '%') {
     487                 :       7650 :                     percent = !percent;
     488 [ +  + ][ +  + ]:      25110 :                 } else if (percent && *i == '[') {
                 [ +  + ]
     489 [ +  - ][ +  - ]:        180 :                     while (i != formatString.end()) {
                 [ +  - ]
     490         [ +  + ]:        180 :                         if (*i == ']') {
     491                 :         45 :                             numFormat++;
     492         [ +  - ]:         45 :                             if (argListTok)
     493         [ +  - ]:         45 :                                 argListTok = argListTok->nextArgument();
     494                 :         45 :                             percent = false;
     495                 :         45 :                             break;
     496                 :            :                         }
     497                 :        135 :                         ++i;
     498                 :            :                     }
     499 [ +  - ][ +  - ]:         45 :                     if (i == formatString.end())
                 [ -  + ]
     500                 :          0 :                         break;
     501         [ +  + ]:      25065 :                 } else if (percent) {
     502                 :       7155 :                     percent = false;
     503                 :            : 
     504                 :       7155 :                     bool _continue = false;
     505         [ +  - ]:       7155 :                     std::string width;
     506 [ +  - ][ +  - ]:       9900 :                     while (i != formatString.end() && *i != ']' && !std::isalpha(*i)) {
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     507         [ +  + ]:       2745 :                         if (*i == '*') {
     508         [ +  + ]:        450 :                             if (scan)
     509                 :        225 :                                 _continue = true;
     510                 :            :                             else {
     511                 :        225 :                                 numFormat++;
     512         [ +  - ]:        225 :                                 if (argListTok)
     513         [ +  - ]:        225 :                                     argListTok = argListTok->nextArgument();
     514                 :            :                             }
     515         [ +  + ]:       2295 :                         } else if (std::isdigit(*i))
     516         [ +  - ]:       1710 :                             width += *i;
     517                 :       2745 :                         ++i;
     518                 :            :                     }
     519 [ +  - ][ +  - ]:       7155 :                     if (i == formatString.end())
                 [ +  + ]
     520                 :            :                         break;
     521         [ +  + ]:       7110 :                     if (_continue)
     522                 :        225 :                         continue;
     523                 :            : 
     524 [ +  + ][ +  + ]:       6885 :                     if (scan || *i != 'm') { // %m is a non-standard extension that requires no parameter on print functions.
                 [ +  + ]
     525                 :       6840 :                         numFormat++;
     526                 :            : 
     527                 :            :                         // Perform type checks
     528 [ +  + ][ +  - ]:       6840 :                         if (argListTok && Token::Match(argListTok->next(), "[,)]")) { // We can currently only check the type of arguments matching this simple pattern.
         [ +  + ][ +  + ]
     529                 :       4860 :                             const Variable *variableInfo = argListTok->variable();
     530         [ +  + ]:       4860 :                             const Token* varTypeTok = variableInfo ? variableInfo->typeStartToken() : NULL;
     531 [ +  + ][ +  - ]:       4860 :                             if (varTypeTok && varTypeTok->str() == "static")
         [ -  + ][ -  + ]
     532                 :          0 :                                 varTypeTok = varTypeTok->next();
     533                 :            : 
     534 [ +  + ][ +  + ]:       4860 :                             if (scan && varTypeTok) {
     535 [ +  - ][ +  - ]:        405 :                                 if (warning && ((!variableInfo->isPointer() && !variableInfo->isArray()) || varTypeTok->strAt(-1) == "const"))
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
                 [ -  + ]
     536         [ #  # ]:          0 :                                     invalidScanfArgTypeError(tok, tok->str(), numFormat);
     537                 :            : 
     538 [ +  - ][ +  - ]:        405 :                                 if (*i == 's' && variableInfo && isKnownType(variableInfo, varTypeTok) && variableInfo->isArray() && (variableInfo->dimensions().size() == 1) && variableInfo->dimensions()[0].known) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     539 [ +  - ][ +  + ]:        360 :                                     if (!width.empty()) {
     540         [ +  - ]:        315 :                                         int numWidth = std::atoi(width.c_str());
     541 [ +  - ][ +  + ]:        315 :                                         if (numWidth != (variableInfo->dimension(0) - 1))
     542         [ +  - ]:        225 :                                             invalidScanfFormatWidthError(tok, numFormat, numWidth, variableInfo);
     543                 :            :                                     }
     544                 :        405 :                                 }
     545 [ +  + ][ +  - ]:       4455 :                             } else if (!scan && warning) {
     546   [ +  +  +  +  :       4050 :                                 switch (*i) {
          +  +  +  +  +  
                      - ]
     547                 :            :                                 case 's':
     548 [ +  + ][ +  - ]:        360 :                                     if (variableInfo && argListTok->type() != Token::eString && isKnownType(variableInfo, varTypeTok) && (!variableInfo->isPointer() && !variableInfo->isArray()))
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
                 [ +  + ]
     549         [ +  - ]:        135 :                                         invalidPrintfArgTypeError_s(tok, numFormat);
     550                 :        360 :                                     break;
     551                 :            :                                 case 'n':
     552 [ +  + ][ +  - ]:        270 :                                     if ((varTypeTok && isKnownType(variableInfo, varTypeTok) && ((!variableInfo->isPointer() && !variableInfo->isArray()) || varTypeTok->strAt(-1) == "const")) || argListTok->type() == Token::eString)
         [ +  - ][ +  + ]
         [ -  + ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
     553         [ +  - ]:        225 :                                         invalidPrintfArgTypeError_n(tok, numFormat);
     554                 :        270 :                                     break;
     555                 :            :                                 case 'c':
     556                 :            :                                 case 'x':
     557                 :            :                                 case 'X':
     558                 :            :                                 case 'o':
     559 [ +  + ][ +  - ]:        405 :                                     if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "bool|short|long|int|char|size_t") && !variableInfo->isPointer() && !variableInfo->isArray())
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
     560         [ +  - ]:         90 :                                         invalidPrintfArgTypeError_int(tok, numFormat, *i);
     561         [ +  + ]:        315 :                                     else if (argListTok->type() == Token::eString)
     562         [ +  - ]:         45 :                                         invalidPrintfArgTypeError_int(tok, numFormat, *i);
     563                 :        405 :                                     break;
     564                 :            :                                 case 'd':
     565                 :            :                                 case 'i':
     566 [ +  + ][ +  - ]:        540 :                                     if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
         [ +  + ][ +  + ]
         [ +  - ][ +  + ]
     567 [ +  + ][ +  - ]:        225 :                                         if ((varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "bool|short|long|int")) && varTypeTok->str() != "char")
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
     568         [ +  - ]:        135 :                                             invalidPrintfArgTypeError_sint(tok, numFormat, *i);
     569         [ +  + ]:        315 :                                     } else if (argListTok->type() == Token::eString)
     570         [ +  - ]:         45 :                                         invalidPrintfArgTypeError_sint(tok, numFormat, *i);
     571                 :        540 :                                     break;
     572                 :            :                                 case 'u':
     573 [ +  + ][ +  - ]:        945 :                                     if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !variableInfo->isPointer() && !variableInfo->isArray()) {
         [ +  + ][ +  + ]
         [ +  - ][ +  + ]
     574 [ -  + ][ #  # ]:        225 :                                         if ((!varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "char|short|long|int|size_t")) && varTypeTok->str() != "bool")
         [ #  # ][ +  - ]
         [ +  + ][ +  + ]
     575         [ +  - ]:        180 :                                             invalidPrintfArgTypeError_uint(tok, numFormat, *i);
     576         [ +  + ]:        720 :                                     } else if (argListTok->type() == Token::eString)
     577         [ +  - ]:         45 :                                         invalidPrintfArgTypeError_uint(tok, numFormat, *i);
     578                 :        945 :                                     break;
     579                 :            :                                 case 'p':
     580 [ +  - ][ +  - ]:        270 :                                     if (varTypeTok && isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "short|long|int|size_t") && !variableInfo->isPointer() && !variableInfo->isArray())
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
     581         [ +  - ]:        135 :                                         invalidPrintfArgTypeError_p(tok, numFormat);
     582         [ -  + ]:        135 :                                     else if (argListTok->type() == Token::eString)
     583         [ #  # ]:          0 :                                         invalidPrintfArgTypeError_p(tok, numFormat);
     584                 :        270 :                                     break;
     585                 :            :                                 case 'e':
     586                 :            :                                 case 'E':
     587                 :            :                                 case 'f':
     588                 :            :                                 case 'g':
     589                 :            :                                 case 'G':
     590 [ +  + ][ +  - ]:        315 :                                     if (varTypeTok && ((isKnownType(variableInfo, varTypeTok) && !Token::Match(varTypeTok, "float|double")) || variableInfo->isPointer() || variableInfo->isArray()))
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
         [ -  + ][ +  + ]
     591         [ +  - ]:        180 :                                         invalidPrintfArgTypeError_float(tok, numFormat, *i);
     592         [ +  + ]:        135 :                                     else if (argListTok->type() == Token::eString)
     593         [ +  - ]:         45 :                                         invalidPrintfArgTypeError_float(tok, numFormat, *i);
     594                 :        315 :                                     break;
     595                 :            :                                 case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
     596                 :            :                                 case 'l': // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
     597                 :            :                                     // If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
     598 [ +  - ][ +  - ]:        540 :                                     if (i != formatString.end() && *(i+1) == *i) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     599 [ +  - ][ +  - ]:        270 :                                         if (i+1 != formatString.end() && !isalpha(*(i+2))) {
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
                 [ +  + ]
     600         [ +  - ]:         90 :                                             std::string modifier;
     601         [ +  - ]:         90 :                                             modifier += *i;
     602 [ +  - ][ +  - ]:         90 :                                             modifier += *(i+1);
     603 [ +  - ][ +  - ]:         90 :                                             invalidLengthModifierError(tok, numFormat, modifier);
     604                 :            :                                         }
     605                 :            :                                     } else {
     606 [ +  - ][ +  - ]:        270 :                                         if (i != formatString.end() && !isalpha(*(i+1))) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     607         [ +  - ]:         90 :                                             std::string modifier;
     608         [ +  - ]:         90 :                                             modifier += *i;
     609 [ +  - ][ +  - ]:         90 :                                             invalidLengthModifierError(tok, numFormat, modifier);
     610                 :            :                                         }
     611                 :            :                                     }
     612                 :        540 :                                     break;
     613                 :            :                                 case 'j': // intmax_t or uintmax_t
     614                 :            :                                 case 'z': // size_t
     615                 :            :                                 case 't': // ptrdiff_t
     616                 :            :                                 case 'L': // long double
     617                 :            :                                     // Expect an alphabetical character after these specifiers
     618 [ +  - ][ +  - ]:        405 :                                     if (i != formatString.end() && !isalpha(*(i+1))) {
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
     619         [ +  - ]:        180 :                                         std::string modifier;
     620         [ +  - ]:        180 :                                         modifier += *i;
     621 [ +  - ][ +  - ]:        180 :                                         invalidLengthModifierError(tok, numFormat, modifier);
     622                 :            :                                     }
     623                 :        405 :                                     break;
     624                 :            :                                 default:
     625                 :       4860 :                                     break;
     626                 :            :                                 }
     627                 :            :                             }
     628                 :            :                         }
     629                 :            : 
     630         [ +  + ]:       6840 :                         if (argListTok)
     631         [ +  - ]:       6885 :                             argListTok = argListTok->nextArgument(); // Find next argument
     632 [ +  - ][ +  + ]:       7155 :                     }
     633                 :            :                 }
     634                 :            :             }
     635                 :            : 
     636                 :            :             // Count printf/scanf parameters..
     637                 :       5805 :             unsigned int numFunction = 0;
     638         [ +  + ]:      12600 :             while (argListTok2) {
     639                 :       6795 :                 numFunction++;
     640         [ +  - ]:       6795 :                 argListTok2 = argListTok2->nextArgument(); // Find next argument
     641                 :            :             }
     642                 :            : 
     643                 :            :             // Mismatching number of parameters => warning
     644         [ +  + ]:       5805 :             if (numFormat != numFunction)
     645         [ +  - ]:       5805 :                 wrongPrintfScanfArgumentsError(tok, tok->str(), numFormat, numFunction);
     646                 :      38469 :         }
     647                 :            :     }
     648                 :       3796 : }
     649                 :            : 
     650                 :        990 : void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok,
     651                 :            :         const std::string &functionName,
     652                 :            :         unsigned int numFormat,
     653                 :            :         unsigned int numFunction)
     654                 :            : {
     655         [ +  + ]:        990 :     Severity::SeverityType severity = numFormat > numFunction ? Severity::error : Severity::warning;
     656 [ +  + ][ +  - ]:        990 :     if (severity != Severity::error && !_settings->isEnabled("style"))
         [ +  - ][ -  + ]
         [ +  + ][ +  - ]
         [ +  + ][ -  + ]
         [ #  # ][ #  # ]
     657                 :        990 :         return;
     658                 :            : 
     659                 :        990 :     std::ostringstream errmsg;
     660         [ +  - ]:        990 :     errmsg << functionName
     661         [ +  - ]:        990 :            << " format string has "
     662         [ +  - ]:        990 :            << numFormat
     663         [ +  - ]:        990 :            << " parameters but "
     664 [ +  + ][ +  - ]:       1980 :            << (numFormat > numFunction ? "only " : "")
     665         [ +  - ]:        990 :            << numFunction
     666         [ +  - ]:        990 :            << " are given.";
     667                 :            : 
     668 [ +  - ][ +  - ]:        990 :     reportError(tok, severity, "wrongPrintfScanfArgNum", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     669                 :            : }
     670                 :            : 
     671                 :         45 : void CheckIO::invalidScanfArgTypeError(const Token* tok, const std::string &functionName, unsigned int numFormat)
     672                 :            : {
     673                 :         45 :     std::ostringstream errmsg;
     674 [ +  - ][ +  - ]:         45 :     errmsg << functionName << " argument no. " << numFormat << ": requires a non-const pointer or array as argument.";
         [ +  - ][ +  - ]
     675 [ +  - ][ +  - ]:         45 :     reportError(tok, Severity::warning, "invalidScanfArgType", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     676                 :         45 : }
     677                 :        180 : void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, unsigned int numFormat)
     678                 :            : {
     679                 :        180 :     std::ostringstream errmsg;
     680 [ +  - ][ +  - ]:        180 :     errmsg << "%s in format string (no. " << numFormat << ") requires a char* given in the argument list.";
                 [ +  - ]
     681 [ +  - ][ +  - ]:        180 :     reportError(tok, Severity::warning, "invalidPrintfArgType_s", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     682                 :        180 : }
     683                 :        270 : void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, unsigned int numFormat)
     684                 :            : {
     685                 :        270 :     std::ostringstream errmsg;
     686 [ +  - ][ +  - ]:        270 :     errmsg << "%n in format string (no. " << numFormat << ") requires a pointer to an non-const integer given in the argument list.";
                 [ +  - ]
     687 [ +  - ][ +  - ]:        270 :     reportError(tok, Severity::warning, "invalidPrintfArgType_n", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     688                 :        270 : }
     689                 :        180 : void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, unsigned int numFormat)
     690                 :            : {
     691                 :        180 :     std::ostringstream errmsg;
     692 [ +  - ][ +  - ]:        180 :     errmsg << "%p in format string (no. " << numFormat << ") requires an address given in the argument list.";
                 [ +  - ]
     693 [ +  - ][ +  - ]:        180 :     reportError(tok, Severity::warning, "invalidPrintfArgType_p", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     694                 :        180 : }
     695                 :        180 : void CheckIO::invalidPrintfArgTypeError_int(const Token* tok, unsigned int numFormat, char c)
     696                 :            : {
     697                 :        180 :     std::ostringstream errmsg;
     698 [ +  - ][ +  - ]:        180 :     errmsg << "%" << c << " in format string (no. " << numFormat << ") requires an integer given in the argument list.";
         [ +  - ][ +  - ]
                 [ +  - ]
     699 [ +  - ][ +  - ]:        180 :     reportError(tok, Severity::warning, "invalidPrintfArgType_int", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     700                 :        180 : }
     701                 :        270 : void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, unsigned int numFormat, char c)
     702                 :            : {
     703                 :        270 :     std::ostringstream errmsg;
     704 [ +  - ][ +  - ]:        270 :     errmsg << "%" << c << " in format string (no. " << numFormat << ") requires an unsigned integer given in the argument list.";
         [ +  - ][ +  - ]
                 [ +  - ]
     705 [ +  - ][ +  - ]:        270 :     reportError(tok, Severity::warning, "invalidPrintfArgType_uint", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     706                 :        270 : }
     707                 :        225 : void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, char c)
     708                 :            : {
     709                 :        225 :     std::ostringstream errmsg;
     710 [ +  - ][ +  - ]:        225 :     errmsg << "%" << c << " in format string (no. " << numFormat << ") requires a signed integer given in the argument list.";
         [ +  - ][ +  - ]
                 [ +  - ]
     711 [ +  - ][ +  - ]:        225 :     reportError(tok, Severity::warning, "invalidPrintfArgType_sint", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     712                 :        225 : }
     713                 :        270 : void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, char c)
     714                 :            : {
     715                 :        270 :     std::ostringstream errmsg;
     716 [ +  - ][ +  - ]:        270 :     errmsg << "%" << c << " in format string (no. " << numFormat << ") requires a floating point number given in the argument list.";
         [ +  - ][ +  - ]
                 [ +  - ]
     717 [ +  - ][ +  - ]:        270 :     reportError(tok, Severity::warning, "invalidPrintfArgType_float", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     718                 :        270 : }
     719                 :        360 : void CheckIO::invalidLengthModifierError(const Token* tok, unsigned int numFormat, std::string& modifier)
     720                 :            : {
     721                 :        360 :     std::ostringstream errmsg;
     722 [ +  - ][ +  - ]:        360 :     errmsg << "'" << modifier << "' in format string (no. " << numFormat << ") is a length modifier and cannot be used without a conversion specifier.";
         [ +  - ][ +  - ]
                 [ +  - ]
     723 [ +  - ][ +  - ]:        360 :     reportError(tok, Severity::warning, "invalidLengthModifierError", errmsg.str());
         [ +  - ][ +  - ]
                 [ +  - ]
     724                 :        360 : }
     725                 :            : 
     726                 :        270 : void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var)
     727                 :            : {
     728                 :        270 :     std::ostringstream errmsg;
     729                 :        270 :     Severity::SeverityType severity = Severity::warning;
     730                 :        270 :     bool inconclusive = false;
     731                 :            : 
     732         [ +  + ]:        270 :     if (var) {
     733 [ +  - ][ +  + ]:        225 :         if (var->dimension(0) > width) {
     734         [ +  + ]:         90 :             if (!_settings->inconclusive)
     735                 :        270 :                 return;
     736                 :         45 :             inconclusive = true;
     737 [ +  - ][ +  - ]:         45 :             errmsg << "Width " << width << " given in format string (no. " << numFormat << ") is smaller than destination buffer"
         [ +  - ][ +  - ]
                 [ +  - ]
     738 [ +  - ][ +  - ]:         90 :                    << " '" << var->name() << "[" << var->dimension(0) << "]'.";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     739                 :            :         } else {
     740 [ +  - ][ +  - ]:        135 :             errmsg << "Width " << width << " given in format string (no. " << numFormat << ") is larger than destination buffer '"
         [ +  - ][ +  - ]
                 [ +  - ]
     741 [ +  - ][ +  - ]:        270 :                    << var->name() << "[" << var->dimension(0) << "]', use %" << (var->dimension(0) - 1) << "s to prevent overflowing it.";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     742                 :        135 :             severity = Severity::error;
     743                 :            :         }
     744                 :            : 
     745                 :            :     } else
     746 [ +  - ][ +  - ]:         45 :         errmsg << "Width " << width << " given in format string (no. " << numFormat << ") doesn't match destination buffer.";
         [ +  - ][ +  - ]
                 [ +  - ]
     747                 :            : 
     748 [ +  + ][ +  - ]:        225 :     if (severity == Severity::error || _settings->isEnabled("style"))
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
         [ +  + ][ +  + ]
         [ #  # ][ #  # ]
     749 [ +  - ][ +  - ]:        270 :         reportError(tok, severity, "invalidScanfFormatWidth", errmsg.str(), inconclusive);
         [ +  - ][ +  - ]
                 [ +  - ]
     750 [ +  - ][ +  - ]:        135 : }

Generated by: LCOV version 1.9