2012-05-20 11:57:07 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2014-02-15 07:45:39 +01:00
* Copyright ( C ) 2007 - 2014 Daniel Marjamäki and Cppcheck team .
2012-05-20 11:57:07 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checkio.h"
# include "tokenize.h"
# include "token.h"
# include "errorlogger.h"
# include "symboldatabase.h"
# include <cctype>
2012-06-23 07:52:52 +02:00
# include <cstdlib>
2012-05-20 11:57:07 +02:00
//---------------------------------------------------------------------------
// Register CheckIO..
namespace {
CheckIO instance ;
}
//---------------------------------------------------------------------------
// std::cout << std::cout;
//---------------------------------------------------------------------------
void CheckIO : : checkCoutCerrMisusage ( )
{
2012-10-30 15:52:45 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
bool firstCout = false ;
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " ( " )
tok = tok - > link ( ) ;
if ( Token : : Match ( tok , " std :: cout|cerr " ) ) {
if ( firstCout & & tok - > strAt ( - 1 ) = = " << " & & tok - > strAt ( 3 ) ! = " . " ) {
coutCerrMisusageError ( tok , tok - > strAt ( 2 ) ) ;
firstCout = false ;
} else if ( tok - > strAt ( 3 ) = = " << " )
firstCout = true ;
} else if ( firstCout & & tok - > str ( ) = = " ; " )
2012-05-20 11:57:07 +02:00
firstCout = false ;
2012-10-30 15:52:45 +01:00
}
2012-05-20 11:57:07 +02:00
}
}
void CheckIO : : coutCerrMisusageError ( const Token * tok , const std : : string & streamName )
{
reportError ( tok , Severity : : error , " coutCerrMisusage " , " Invalid usage of output stream: '<< std:: " + streamName + " '. " ) ;
}
//---------------------------------------------------------------------------
// fflush(stdin) <- fflush only applies to output streams in ANSI C
2012-07-21 15:54:04 +02:00
// fread(); fwrite(); <- consecutive read/write statements require repositioning in between
2012-05-22 14:30:22 +02:00
// fopen("","r"); fwrite(); <- write to read-only file (or vice versa)
// fclose(); fread(); <- Use closed file
2012-05-20 11:57:07 +02:00
//---------------------------------------------------------------------------
2014-03-17 11:02:03 +01:00
enum OpenMode { CLOSED , READ_MODE , WRITE_MODE , RW_MODE , UNKNOWN_OM } ;
2012-05-22 14:30:22 +02:00
static OpenMode getMode ( const std : : string & str )
2012-05-20 11:57:07 +02:00
{
2012-05-22 14:30:22 +02:00
if ( str . find ( ' + ' , 1 ) ! = std : : string : : npos )
return RW_MODE ;
else if ( str . find ( ' w ' ) ! = std : : string : : npos | | str . find ( ' a ' ) ! = std : : string : : npos )
return WRITE_MODE ;
else if ( str . find ( ' r ' ) ! = std : : string : : npos )
return READ_MODE ;
2014-03-17 11:02:03 +01:00
return UNKNOWN_OM ;
2012-05-22 14:30:22 +02:00
}
2012-05-22 15:43:40 +02:00
struct Filepointer {
OpenMode mode ;
unsigned int mode_indent ;
enum Operation { NONE , UNIMPORTANT , READ , WRITE , POSITIONING , OPEN , CLOSE , UNKNOWN_OP } lastOperation ;
unsigned int op_indent ;
2014-03-17 11:02:03 +01:00
enum AppendMode { UNKNOWN_AM , APPEND , APPEND_EX } ;
AppendMode append_mode ;
Filepointer ( OpenMode mode_ = UNKNOWN_OM )
: mode ( mode_ ) , mode_indent ( 0 ) , lastOperation ( NONE ) , op_indent ( 0 ) , append_mode ( UNKNOWN_AM ) {
2012-05-22 15:43:40 +02:00
}
} ;
2012-05-22 14:30:22 +02:00
void CheckIO : : checkFileUsage ( )
{
static const char * _whitelist [ ] = {
2014-03-12 19:22:44 +01:00
" clearerr " , " feof " , " ferror " , " fgetpos " , " ftell " , " setbuf " , " setvbuf " , " ungetc " , " ungetwc "
2012-05-22 14:30:22 +02:00
} ;
static const std : : set < std : : string > whitelist ( _whitelist , _whitelist + sizeof ( _whitelist ) / sizeof ( * _whitelist ) ) ;
2014-03-12 19:22:44 +01:00
const bool windows = _settings - > isWindowsPlatform ( ) ;
2012-05-22 14:30:22 +02:00
std : : map < unsigned int , Filepointer > filepointers ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-07-08 23:39:46 +02:00
std : : size_t varListSize = symbolDatabase - > getVariableListSize ( ) ;
for ( std : : size_t i = 1 ; i < varListSize ; + + i ) {
2012-05-22 14:30:22 +02:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( i ) ;
2013-07-20 12:31:04 +02:00
if ( ! var | | ! var - > declarationId ( ) | | var - > isArray ( ) | | ! Token : : simpleMatch ( var - > typeStartToken ( ) , " FILE * " ) )
2012-05-22 14:30:22 +02:00
continue ;
2012-06-24 18:57:17 +02:00
if ( var - > isLocal ( ) ) {
if ( var - > nameToken ( ) - > strAt ( 1 ) = = " ( " ) // initialize by calling "ctor"
2014-03-17 11:02:03 +01:00
filepointers . insert ( std : : make_pair ( var - > declarationId ( ) , Filepointer ( UNKNOWN_OM ) ) ) ;
2012-06-24 18:57:17 +02:00
else
2013-07-20 12:31:04 +02:00
filepointers . insert ( std : : make_pair ( var - > declarationId ( ) , Filepointer ( CLOSED ) ) ) ;
2012-06-24 18:57:17 +02:00
} else {
2014-03-17 11:02:03 +01:00
filepointers . insert ( std : : make_pair ( var - > declarationId ( ) , Filepointer ( UNKNOWN_OM ) ) ) ;
2012-05-22 14:30:22 +02:00
// TODO: If all fopen calls we find open the file in the same type, we can set Filepointer::mode
}
}
2012-10-30 15:52:45 +01:00
std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t j = 0 ; j < functions ; + + j ) {
const Scope * scope = symbolDatabase - > functionScopes [ j ] ;
unsigned int indent = 0 ;
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " )
indent + + ;
else if ( tok - > str ( ) = = " } " ) {
indent - - ;
for ( std : : map < unsigned int , Filepointer > : : iterator i = filepointers . begin ( ) ; i ! = filepointers . end ( ) ; + + i ) {
if ( indent < i - > second . mode_indent ) {
i - > second . mode_indent = 0 ;
2014-03-17 11:02:03 +01:00
i - > second . mode = UNKNOWN_OM ;
2012-10-30 15:52:45 +01:00
}
if ( indent < i - > second . op_indent ) {
i - > second . op_indent = 0 ;
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
2012-05-22 14:30:22 +02:00
}
2013-02-15 17:30:43 +01:00
} else if ( tok - > str ( ) = = " return " | | tok - > str ( ) = = " continue " | | tok - > str ( ) = = " break " ) { // Reset upon return, continue or break
for ( std : : map < unsigned int , Filepointer > : : iterator i = filepointers . begin ( ) ; i ! = filepointers . end ( ) ; + + i ) {
i - > second . mode_indent = 0 ;
2014-03-17 11:02:03 +01:00
i - > second . mode = UNKNOWN_OM ;
2013-02-15 17:30:43 +01:00
i - > second . op_indent = 0 ;
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
2014-03-12 19:22:44 +01:00
} else if ( tok - > varId ( ) & & Token : : Match ( tok , " %var% = " ) & &
( tok - > strAt ( 2 ) ! = " fopen " & & tok - > strAt ( 2 ) ! = " freopen " & & tok - > strAt ( 2 ) ! = " tmpfile " & &
( windows ? ( tok - > str ( ) ! = " _wfopen " & & tok - > str ( ) ! = " _wfreopen " ) : true ) ) ) {
2012-10-30 15:52:45 +01:00
std : : map < unsigned int , Filepointer > : : iterator i = filepointers . find ( tok - > varId ( ) ) ;
if ( i ! = filepointers . end ( ) ) {
2014-03-17 11:02:03 +01:00
i - > second . mode = UNKNOWN_OM ;
2012-05-22 14:30:22 +02:00
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
2012-10-30 15:52:45 +01:00
} else if ( Token : : Match ( tok , " %var% ( " ) & & tok - > previous ( ) & & ( ! tok - > previous ( ) - > isName ( ) | | Token : : Match ( tok - > previous ( ) , " return|throw " ) ) ) {
std : : string mode ;
const Token * fileTok = 0 ;
Filepointer : : Operation operation = Filepointer : : NONE ;
2014-03-12 19:22:44 +01:00
if ( ( tok - > str ( ) = = " fopen " | | tok - > str ( ) = = " freopen " | | tok - > str ( ) = = " tmpfile " | |
( windows & & ( tok - > str ( ) = = " _wfopen " | | tok - > str ( ) = = " _wfreopen " ) ) ) & &
tok - > strAt ( - 1 ) = = " = " ) {
2012-10-30 15:52:45 +01:00
if ( tok - > str ( ) ! = " tmpfile " ) {
const Token * modeTok = tok - > tokAt ( 2 ) - > nextArgument ( ) ;
if ( modeTok & & modeTok - > type ( ) = = Token : : eString )
mode = modeTok - > strValue ( ) ;
} else
mode = " wb+ " ;
fileTok = tok - > tokAt ( - 2 ) ;
operation = Filepointer : : OPEN ;
2014-03-12 19:22:44 +01:00
} else if ( windows & & Token : : Match ( tok , " fopen_s|freopen_s|_wfopen_s|_wfreopen_s ( & %var% " ) ) {
const Token * modeTok = tok - > tokAt ( 2 ) - > nextArgument ( ) - > nextArgument ( ) ;
if ( modeTok & & modeTok - > type ( ) = = Token : : eString )
mode = modeTok - > strValue ( ) ;
fileTok = tok - > tokAt ( 3 ) ;
operation = Filepointer : : OPEN ;
} else if ( ( tok - > str ( ) = = " rewind " | | tok - > str ( ) = = " fseek " | | tok - > str ( ) = = " fsetpos " | | tok - > str ( ) = = " fflush " ) | |
( windows & & tok - > str ( ) = = " _fseeki64 " ) ) {
2012-10-30 15:52:45 +01:00
if ( Token : : simpleMatch ( tok , " fflush ( stdin ) " ) )
fflushOnInputStreamError ( tok , tok - > strAt ( 2 ) ) ;
else {
fileTok = tok - > tokAt ( 2 ) ;
operation = Filepointer : : POSITIONING ;
}
2014-03-12 19:22:44 +01:00
} else if ( tok - > str ( ) = = " fgetc " | | tok - > str ( ) = = " fgetwc " | |
tok - > str ( ) = = " fgets " | | tok - > str ( ) = = " fgetws " | | tok - > str ( ) = = " fread " | |
tok - > str ( ) = = " fscanf " | | tok - > str ( ) = = " fwscanf " | | tok - > str ( ) = = " getc " | |
( windows & & ( tok - > str ( ) = = " fscanf_s " | | tok - > str ( ) = = " fwscanf_s " ) ) ) {
if ( tok - > str ( ) . find ( " scanf " ) ! = std : : string : : npos )
2012-10-30 15:52:45 +01:00
fileTok = tok - > tokAt ( 2 ) ;
else
fileTok = tok - > linkAt ( 1 ) - > previous ( ) ;
operation = Filepointer : : READ ;
2014-03-12 19:22:44 +01:00
} else if ( tok - > str ( ) = = " fputc " | | tok - > str ( ) = = " fputwc " | |
tok - > str ( ) = = " fputs " | | tok - > str ( ) = = " fputws " | | tok - > str ( ) = = " fwrite " | |
tok - > str ( ) = = " fprintf " | | tok - > str ( ) = = " fwprintf " | | tok - > str ( ) = = " putcc " | |
( windows & & ( tok - > str ( ) = = " fprintf_s " | | tok - > str ( ) = = " fwprintf_s " ) ) ) {
if ( tok - > str ( ) . find ( " printf " ) ! = std : : string : : npos )
2012-10-30 15:52:45 +01:00
fileTok = tok - > tokAt ( 2 ) ;
else
fileTok = tok - > linkAt ( 1 ) - > previous ( ) ;
operation = Filepointer : : WRITE ;
} else if ( tok - > str ( ) = = " fclose " ) {
2012-05-22 14:30:22 +02:00
fileTok = tok - > tokAt ( 2 ) ;
2012-10-30 15:52:45 +01:00
operation = Filepointer : : CLOSE ;
} else if ( whitelist . find ( tok - > str ( ) ) ! = whitelist . end ( ) ) {
2012-05-22 14:30:22 +02:00
fileTok = tok - > tokAt ( 2 ) ;
2014-03-12 19:22:44 +01:00
if ( ( tok - > str ( ) = = " ungetc " | | tok - > str ( ) = = " ungetwc " ) & & fileTok )
2012-10-30 15:52:45 +01:00
fileTok = fileTok - > nextArgument ( ) ;
operation = Filepointer : : UNIMPORTANT ;
2013-02-15 17:30:43 +01:00
} else if ( ! Token : : Match ( tok , " if|for|while|catch|switch " ) ) {
2012-10-30 15:52:45 +01:00
const Token * const end2 = tok - > linkAt ( 1 ) ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) & & filepointers . find ( tok2 - > varId ( ) ) ! = filepointers . end ( ) ) {
fileTok = tok2 ;
operation = Filepointer : : UNKNOWN_OP ; // Assume that repositioning was last operation and that the file is opened now
break ;
}
2012-05-22 14:30:22 +02:00
}
}
2013-03-15 06:42:46 +01:00
while ( Token : : Match ( fileTok , " %var% . " ) )
fileTok = fileTok - > tokAt ( 2 ) ;
2012-10-30 15:52:45 +01:00
if ( ! fileTok | | ! fileTok - > varId ( ) )
continue ;
2012-05-22 14:30:22 +02:00
2012-10-30 15:52:45 +01:00
if ( filepointers . find ( fileTok - > varId ( ) ) = = filepointers . end ( ) ) { // function call indicates: Its a File
2014-03-17 11:02:03 +01:00
filepointers . insert ( std : : make_pair ( fileTok - > varId ( ) , Filepointer ( UNKNOWN_OM ) ) ) ;
2012-10-30 15:52:45 +01:00
}
Filepointer & f = filepointers [ fileTok - > varId ( ) ] ;
switch ( operation ) {
case Filepointer : : OPEN :
f . mode = getMode ( mode ) ;
2014-03-17 11:02:03 +01:00
if ( mode . find ( ' a ' ) ! = std : : string : : npos ) {
if ( f . mode = = RW_MODE )
f . append_mode = Filepointer : : APPEND_EX ;
else
f . append_mode = Filepointer : : APPEND ;
}
2012-10-30 15:52:45 +01:00
f . mode_indent = indent ;
break ;
case Filepointer : : POSITIONING :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
2014-03-17 11:02:03 +01:00
else if ( f . append_mode = = Filepointer : : APPEND & & _settings - > isEnabled ( " warning " ) )
seekOnAppendedFileError ( tok ) ;
2012-10-30 15:52:45 +01:00
break ;
case Filepointer : : READ :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
else if ( f . mode = = WRITE_MODE )
readWriteOnlyFileError ( tok ) ;
else if ( f . lastOperation = = Filepointer : : WRITE )
ioWithoutPositioningError ( tok ) ;
break ;
case Filepointer : : WRITE :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
else if ( f . mode = = READ_MODE )
writeReadOnlyFileError ( tok ) ;
else if ( f . lastOperation = = Filepointer : : READ )
ioWithoutPositioningError ( tok ) ;
break ;
case Filepointer : : CLOSE :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
else
f . mode = CLOSED ;
f . mode_indent = indent ;
break ;
case Filepointer : : UNIMPORTANT :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
break ;
case Filepointer : : UNKNOWN_OP :
2014-03-17 11:02:03 +01:00
f . mode = UNKNOWN_OM ;
2012-10-30 15:52:45 +01:00
f . mode_indent = 0 ;
break ;
default :
break ;
}
if ( operation ! = Filepointer : : NONE & & operation ! = Filepointer : : UNIMPORTANT ) {
f . op_indent = indent ;
f . lastOperation = operation ;
}
2012-05-22 14:30:22 +02:00
}
}
2012-12-08 09:26:10 +01:00
for ( std : : map < unsigned int , Filepointer > : : iterator i = filepointers . begin ( ) ; i ! = filepointers . end ( ) ; + + i ) {
i - > second . op_indent = 0 ;
2014-03-17 11:02:03 +01:00
i - > second . mode = UNKNOWN_OM ;
2012-12-08 09:26:10 +01:00
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
2012-05-20 11:57:07 +02:00
}
}
void CheckIO : : fflushOnInputStreamError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error ,
2012-07-13 19:36:58 +02:00
" fflushOnInputStream " , " fflush() called on input stream ' " + varname + " ' results in undefined behaviour. " ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : ioWithoutPositioningError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2012-07-21 15:54:04 +02:00
" IOWithoutPositioning " , " Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour. " ) ;
2012-05-20 11:57:07 +02:00
}
2012-05-22 14:30:22 +02:00
void CheckIO : : readWriteOnlyFileError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2012-07-13 19:36:58 +02:00
" readWriteOnlyFile " , " Read operation on a file that was opened only for writing. " ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : writeReadOnlyFileError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2012-07-13 19:36:58 +02:00
" writeReadOnlyFile " , " Write operation on a file that was opened only for reading. " ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : useClosedFileError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
" useClosedFile " , " Used file that is not opened. " ) ;
}
2014-03-17 11:02:03 +01:00
void CheckIO : : seekOnAppendedFileError ( const Token * tok )
{
reportError ( tok , Severity : : warning ,
" seekOnAppendedFile " , " Repositioning operation performed on a file opened in append mode has no effect. " ) ;
}
2012-05-22 14:30:22 +02:00
2012-05-20 11:57:07 +02:00
//---------------------------------------------------------------------------
// scanf without field width limits can crash with huge input data
//---------------------------------------------------------------------------
void CheckIO : : invalidScanf ( )
{
2013-03-03 11:41:59 +01:00
if ( ! _settings - > isEnabled ( " warning " ) & & ! _settings - > isEnabled ( " portability " ) )
2012-05-20 11:57:07 +02:00
return ;
2012-07-07 13:34:37 +02:00
2014-03-12 19:22:44 +01:00
const bool windows = _settings - > isWindowsPlatform ( ) ;
2012-10-30 15:52:45 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t j = 0 ; j < functions ; + + j ) {
const Scope * scope = symbolDatabase - > functionScopes [ j ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-02-16 11:47:52 +01:00
const Token * formatToken = nullptr ;
2012-10-30 15:52:45 +01:00
if ( Token : : Match ( tok , " scanf|vscanf ( %str% , " ) )
formatToken = tok - > tokAt ( 2 ) ;
else if ( Token : : Match ( tok , " sscanf|vsscanf|fscanf|vfscanf ( " ) ) {
const Token * nextArg = tok - > tokAt ( 2 ) - > nextArgument ( ) ;
if ( nextArg & & nextArg - > type ( ) = = Token : : eString )
formatToken = nextArg ;
else
continue ;
} else
2012-05-20 11:57:07 +02:00
continue ;
2012-10-30 15:52:45 +01:00
bool format = false ;
2012-05-20 11:57:07 +02:00
2013-11-09 16:07:28 +01:00
// scan the string backwards, so we do not need to keep states
2012-10-30 15:52:45 +01:00
const std : : string & formatstr ( formatToken - > str ( ) ) ;
for ( unsigned int i = 1 ; i < formatstr . length ( ) ; i + + ) {
if ( formatstr [ i ] = = ' % ' )
format = ! format ;
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
else if ( ! format )
continue ;
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
else if ( std : : isdigit ( formatstr [ i ] ) | | formatstr [ i ] = = ' * ' ) {
format = false ;
}
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
else if ( std : : isalpha ( formatstr [ i ] ) | | formatstr [ i ] = = ' [ ' ) {
2013-03-03 11:41:59 +01:00
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
2012-10-30 15:52:45 +01:00
invalidScanfError ( tok , false ) ;
2014-03-12 19:22:44 +01:00
else if ( formatstr [ i ] ! = ' n ' & & formatstr [ i ] ! = ' c ' & & ! windows & & _settings - > isEnabled ( " portability " ) )
2012-10-30 15:52:45 +01:00
invalidScanfError ( tok , true ) ; // Warn about libc bug in versions prior to 2.13-25
format = false ;
}
2012-05-20 11:57:07 +02:00
}
}
}
}
2012-07-07 13:34:37 +02:00
void CheckIO : : invalidScanfError ( const Token * tok , bool portability )
2012-05-20 11:57:07 +02:00
{
2012-07-07 13:34:37 +02:00
if ( portability )
reportError ( tok , Severity : : portability ,
" invalidscanf " , " scanf without field width limits can crash with huge input data on some versions of libc. \n "
" scanf without field width limits can crash with huge input data on libc versions older than 2.13-25. Add a field "
" width specifier to fix this problem: \n "
" %i => %3i \n "
" \n "
" Sample program that can crash: \n "
" \n "
" #include <stdio.h> \n "
" int main() \n "
" { \n "
" int a; \n "
" scanf( \" %i \" , &a); \n "
" return 0; \n "
" } \n "
" \n "
" To make it crash: \n "
" perl -e 'print \" 5 \" x2100000' | ./a.out " ) ;
else
reportError ( tok , Severity : : warning ,
" invalidscanf " , " scanf without field width limits can crash with huge input data. \n "
" scanf without field width limits can crash with huge input data. Add a field width "
" specifier to fix this problem: \n "
" %s => %20s \n "
" \n "
" Sample program that can crash: \n "
" \n "
" #include <stdio.h> \n "
" int main() \n "
" { \n "
" char c[5]; \n "
" scanf( \" %s \" , c); \n "
" return 0; \n "
" } \n "
" \n "
" To make it crash, type in more than 5 characters. " ) ;
2012-05-20 11:57:07 +02:00
}
//---------------------------------------------------------------------------
// printf("%u", "xyz"); // Wrong argument type
// printf("%u%s", 1); // Too few arguments
// printf("", 1); // Too much arguments
//---------------------------------------------------------------------------
2013-10-04 17:30:55 +02:00
static bool findFormat ( unsigned int arg , const Token * firstArg ,
const Token * * formatStringTok , const Token * * formatArgTok )
{
const Token * argTok = firstArg ;
for ( unsigned int i = 0 ; i < arg & & argTok ; + + i )
argTok = argTok - > nextArgument ( ) ;
if ( Token : : Match ( argTok , " %str% [,)] " ) ) {
* formatArgTok = argTok - > nextArgument ( ) ;
* formatStringTok = argTok ;
return true ;
} else if ( Token : : Match ( argTok , " %var% [,)] " ) & &
2013-11-01 00:18:13 +01:00
( argTok - > variable ( ) & &
2013-10-04 17:30:55 +02:00
Token : : Match ( argTok - > variable ( ) - > typeStartToken ( ) , " char|wchar_t " ) & &
( argTok - > variable ( ) - > isPointer ( ) | |
( argTok - > variable ( ) - > dimensions ( ) . size ( ) = = 1 & &
argTok - > variable ( ) - > dimensionKnown ( 0 ) & &
argTok - > variable ( ) - > dimension ( 0 ) ! = 0 ) ) ) ) {
* formatArgTok = argTok - > nextArgument ( ) ;
2014-02-16 11:47:52 +01:00
* formatStringTok = nullptr ;
2013-10-04 17:30:55 +02:00
if ( argTok - > variable ( ) ) {
const Token * varTok = argTok - > variable ( ) - > nameToken ( ) ;
if ( Token : : Match ( varTok , " %var% ; %var% = %str% ; " ) & &
varTok - > str ( ) = = varTok - > strAt ( 2 ) & &
Token : : Match ( varTok - > tokAt ( - 4 ) , " const char|wchar_t * const " ) ) {
* formatStringTok = varTok - > tokAt ( 4 ) ;
} else if ( Token : : Match ( varTok , " %var% [ %num% ] = %str% ; " ) & &
Token : : Match ( varTok - > tokAt ( - 2 ) , " const char|wchar_t " ) ) {
* formatStringTok = varTok - > tokAt ( 5 ) ;
}
}
return true ;
}
return false ;
}
2012-05-20 11:57:07 +02:00
void CheckIO : : checkWrongPrintfScanfArguments ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2014-03-12 19:22:44 +01:00
const bool warning = _settings - > isEnabled ( " warning " ) ;
const bool windows = _settings - > isWindowsPlatform ( ) ;
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t j = 0 ; j < functions ; + + j ) {
const Scope * scope = symbolDatabase - > functionScopes [ j ] ;
for ( const Token * tok = scope - > classStart - > next ( ) ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( ! tok - > isName ( ) ) continue ;
const Token * argListTok = 0 ; // Points to first va_list argument
2013-10-04 17:30:55 +02:00
const Token * formatStringTok = 0 ; // Points to format string token
2012-10-30 15:52:45 +01:00
std : : string formatString ;
2014-01-12 12:44:24 +01:00
bool scan = false ;
bool scanf_s = false ;
int formatStringArgNo = - 1 ;
if ( Token : : Match ( tok - > next ( ) , " ( %any% " ) & & _settings - > library . formatstr_function ( tok - > str ( ) ) ) {
const std : : map < int , Library : : ArgumentChecks > & argumentChecks = _settings - > library . argumentChecks . at ( tok - > str ( ) ) ;
2014-02-01 07:40:08 +01:00
for ( std : : map < int , Library : : ArgumentChecks > : : const_iterator i = argumentChecks . begin ( ) ; i ! = argumentChecks . end ( ) ; + + i ) {
2014-01-12 12:44:24 +01:00
if ( i - > second . formatstr ) {
formatStringArgNo = i - > first - 1 ;
2013-07-22 20:21:45 +02:00
break ;
}
}
2014-01-12 12:44:24 +01:00
scan = _settings - > library . formatstr_scan ( tok - > str ( ) ) ;
scanf_s = _settings - > library . formatstr_secure ( tok - > str ( ) ) ;
2013-07-22 20:21:45 +02:00
}
2014-01-12 12:44:24 +01:00
if ( formatStringArgNo > = 0 ) {
// formatstring found in library. Find format string and first argument belonging to format string.
if ( ! findFormat ( formatStringArgNo , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) )
continue ;
} else if ( windows & & Token : : Match ( tok , " Format|AppendFormat ( " ) & &
Token : : Match ( tok - > tokAt ( - 2 ) , " %var% . " ) & & tok - > tokAt ( - 2 ) - > variable ( ) & &
tok - > tokAt ( - 2 ) - > variable ( ) - > typeStartToken ( ) - > str ( ) = = " CString " ) {
2013-10-05 07:47:52 +02:00
// Find second parameter and format string
2013-10-04 17:30:55 +02:00
if ( ! findFormat ( 0 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) )
2012-10-30 15:52:45 +01:00
continue ;
2014-01-12 12:44:24 +01:00
} else if ( Token : : simpleMatch ( tok , " swprintf ( " ) & & Token : : Match ( tok - > tokAt ( 2 ) - > nextArgument ( ) , " %str% " ) ) {
2013-10-05 07:47:52 +02:00
// Find third parameter and format string
2013-10-04 17:30:55 +02:00
if ( ! findFormat ( 1 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) )
2012-10-30 15:52:45 +01:00
continue ;
2014-01-12 12:44:24 +01:00
} else if ( Token : : simpleMatch ( tok , " swprintf ( " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) - > nextArgument ( ) , " %str% " ) ) {
2013-10-05 07:47:52 +02:00
// Find forth parameter and format string
2013-10-04 17:30:55 +02:00
if ( ! findFormat ( 2 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) )
2012-10-30 15:52:45 +01:00
continue ;
2013-10-04 17:30:55 +02:00
} else if ( windows & & Token : : Match ( tok , " sprintf_s|swprintf_s ( " ) ) {
// template <size_t size> int sprintf_s(char (&buffer)[size], const char *format, ...);
if ( findFormat ( 1 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) ) {
if ( ! formatStringTok )
continue ;
}
// int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
else if ( findFormat ( 2 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) ) {
if ( ! formatStringTok )
continue ;
2012-10-30 15:52:45 +01:00
}
2013-10-01 05:49:44 +02:00
} else if ( windows & & Token : : Match ( tok , " _snprintf_s|_snwprintf_s ( " ) ) {
2013-10-04 17:30:55 +02:00
// template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...);
if ( findFormat ( 2 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) ) {
if ( ! formatStringTok )
continue ;
2013-09-30 19:55:21 +02:00
}
2013-10-04 17:30:55 +02:00
// int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...);
else if ( findFormat ( 3 , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) ) {
if ( ! formatStringTok )
continue ;
2013-09-30 19:55:21 +02:00
}
2012-05-20 11:57:07 +02:00
} else {
continue ;
}
2013-10-04 17:30:55 +02:00
if ( formatStringTok )
formatString = formatStringTok - > str ( ) ;
2013-10-05 07:47:52 +02:00
else
continue ;
2013-10-04 17:30:55 +02:00
2012-10-30 15:52:45 +01:00
// Count format string parameters..
unsigned int numFormat = 0 ;
2013-09-30 19:55:21 +02:00
unsigned int numSecure = 0 ;
2012-10-30 15:52:45 +01:00
bool percent = false ;
const Token * argListTok2 = argListTok ;
2013-07-28 15:00:28 +02:00
std : : set < unsigned int > parameterPositionsUsed ;
2012-10-30 15:52:45 +01:00
for ( std : : string : : iterator i = formatString . begin ( ) ; i ! = formatString . end ( ) ; + + i ) {
if ( * i = = ' % ' ) {
percent = ! percent ;
} else if ( percent & & * i = = ' [ ' ) {
while ( i ! = formatString . end ( ) ) {
if ( * i = = ' ] ' ) {
2012-05-20 11:57:07 +02:00
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
2012-10-30 15:52:45 +01:00
percent = false ;
break ;
2012-05-20 11:57:07 +02:00
}
2012-10-30 15:52:45 +01:00
+ + i ;
}
2013-10-01 05:49:44 +02:00
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
2012-10-30 15:52:45 +01:00
if ( i = = formatString . end ( ) )
break ;
} else if ( percent ) {
percent = false ;
bool _continue = false ;
2013-10-01 05:49:44 +02:00
bool skip = false ;
2012-10-30 15:52:45 +01:00
std : : string width ;
2013-07-28 16:13:16 +02:00
unsigned int parameterPosition = 0 ;
bool hasParameterPosition = false ;
2013-10-01 05:49:44 +02:00
while ( i ! = formatString . end ( ) & & * i ! = ' [ ' & & ! std : : isalpha ( * i ) ) {
2012-10-30 15:52:45 +01:00
if ( * i = = ' * ' ) {
2013-10-01 05:49:44 +02:00
skip = true ;
2012-10-30 15:52:45 +01:00
if ( scan )
_continue = true ;
else {
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
}
2013-07-28 15:00:28 +02:00
} else if ( std : : isdigit ( * i ) ) {
2012-10-30 15:52:45 +01:00
width + = * i ;
2013-07-28 15:00:28 +02:00
} else if ( * i = = ' $ ' ) {
parameterPosition = static_cast < unsigned int > ( std : : atoi ( width . c_str ( ) ) ) ;
hasParameterPosition = true ;
width . clear ( ) ;
}
2012-10-30 15:52:45 +01:00
+ + i ;
}
2013-10-08 05:33:37 +02:00
if ( i ! = formatString . end ( ) & & * i = = ' [ ' ) {
2013-10-01 05:49:44 +02:00
while ( i ! = formatString . end ( ) ) {
if ( * i = = ' ] ' ) {
if ( ! skip ) {
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
}
break ;
}
+ + i ;
}
if ( scanf_s & & ! skip ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
_continue = true ;
}
2012-10-30 15:52:45 +01:00
if ( i = = formatString . end ( ) )
break ;
if ( _continue )
continue ;
if ( scan | | * i ! = ' m ' ) { // %m is a non-standard extension that requires no parameter on print functions.
2013-07-28 15:00:28 +02:00
+ + numFormat ;
2013-07-28 16:13:16 +02:00
2013-07-28 15:00:28 +02:00
// Handle parameter positions (POSIX extension) - Ticket #4900
2013-07-28 16:13:16 +02:00
if ( hasParameterPosition ) {
if ( parameterPositionsUsed . find ( parameterPosition ) = = parameterPositionsUsed . end ( ) )
2013-07-28 15:00:28 +02:00
parameterPositionsUsed . insert ( parameterPosition ) ;
else // Parameter already referenced, hence don't consider it a new format
- - numFormat ;
}
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
// Perform type checks
2013-09-03 05:50:19 +02:00
ArgumentInfo argInfo ( argListTok , _settings ) ;
2012-10-30 15:52:45 +01:00
2013-09-03 05:50:19 +02:00
if ( argInfo . typeToken ) {
if ( scan ) {
2013-09-22 06:56:31 +02:00
std : : string specifier ;
bool done = false ;
while ( ! done ) {
switch ( * i ) {
case ' s ' :
specifier + = * i ;
if ( argInfo . variableInfo & & argInfo . isKnownType ( ) & & argInfo . variableInfo - > isArray ( ) & & ( argInfo . variableInfo - > dimensions ( ) . size ( ) = = 1 ) & & argInfo . variableInfo - > dimensions ( ) [ 0 ] . known ) {
if ( ! width . empty ( ) ) {
int numWidth = std : : atoi ( width . c_str ( ) ) ;
if ( numWidth ! = ( argInfo . variableInfo - > dimension ( 0 ) - 1 ) )
invalidScanfFormatWidthError ( tok , numFormat , numWidth , argInfo . variableInfo ) ;
}
}
if ( argListTok - > type ( ) ! = Token : : eString & &
argInfo . isKnownType ( ) & & argInfo . isArrayOrPointer ( ) & &
( ! Token : : Match ( argInfo . typeToken , " char|wchar_t " ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) ) {
2013-10-27 10:48:49 +01:00
if ( ! ( argInfo . isArrayOrPointer ( ) & & argInfo . element & & ! argInfo . typeToken - > isStandardType ( ) ) )
invalidScanfArgTypeError_s ( tok , numFormat , specifier , & argInfo ) ;
2013-09-22 06:56:31 +02:00
}
2013-09-30 19:55:21 +02:00
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
done = true ;
break ;
case ' c ' :
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
2013-09-22 06:56:31 +02:00
done = true ;
break ;
case ' x ' :
case ' X ' :
case ' o ' :
specifier + = * i ;
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . isKnownType ( ) ) {
2013-10-27 10:48:49 +01:00
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( ! argInfo . isArrayOrPointer ( ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) {
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2013-10-27 10:48:49 +01:00
} else {
2013-09-22 06:56:31 +02:00
switch ( specifier [ 0 ] ) {
case ' h ' :
if ( specifier [ 1 ] = = ' h ' ) {
if ( argInfo . typeToken - > str ( ) ! = " char " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " short " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' I ' :
2013-10-03 06:37:40 +02:00
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " & &
argInfo . typeToken - > originalName ( ) ! = " size_t " )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' j ' :
if ( argInfo . typeToken - > originalName ( ) ! = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' z ' :
if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' t ' :
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
default :
if ( argInfo . typeToken - > str ( ) ! = " int " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
}
}
}
done = true ;
break ;
case ' n ' :
case ' d ' :
case ' i ' :
specifier + = * i ;
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( argInfo . isKnownType ( ) ) {
2013-10-27 10:48:49 +01:00
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
} else if ( argInfo . typeToken - > isUnsigned ( ) | |
! argInfo . isArrayOrPointer ( ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) {
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
2013-10-27 10:48:49 +01:00
} else {
2013-09-22 06:56:31 +02:00
switch ( specifier [ 0 ] ) {
case ' h ' :
if ( specifier [ 1 ] = = ' h ' ) {
if ( argInfo . typeToken - > str ( ) ! = " char " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " short " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' I ' :
2013-10-03 06:37:40 +02:00
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
} else if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' j ' :
if ( argInfo . typeToken - > originalName ( ) ! = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' z ' :
2014-01-14 06:09:13 +01:00
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " & &
argInfo . typeToken - > originalName ( ) ! = " ssize_t " )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' t ' :
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
default :
if ( argInfo . typeToken - > str ( ) ! = " int " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
}
}
}
done = true ;
break ;
case ' u ' :
specifier + = * i ;
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . isKnownType ( ) ) {
2013-10-27 10:48:49 +01:00
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( ! argInfo . typeToken - > isUnsigned ( ) | |
! argInfo . isArrayOrPointer ( ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) {
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2013-10-27 10:48:49 +01:00
} else {
2013-09-22 06:56:31 +02:00
switch ( specifier [ 0 ] ) {
case ' h ' :
if ( specifier [ 1 ] = = ' h ' ) {
if ( argInfo . typeToken - > str ( ) ! = " char " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " short " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' I ' :
2013-10-03 06:37:40 +02:00
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
} else if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' j ' :
if ( argInfo . typeToken - > originalName ( ) ! = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' z ' :
if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' t ' :
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
default :
if ( argInfo . typeToken - > str ( ) ! = " int " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
}
}
}
done = true ;
break ;
case ' e ' :
case ' E ' :
case ' f ' :
case ' g ' :
case ' G ' :
case ' a ' :
specifier + = * i ;
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . isKnownType ( ) ) {
2013-10-27 10:48:49 +01:00
if ( ! Token : : Match ( argInfo . typeToken , " float|double " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! argInfo . isArrayOrPointer ( ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) {
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-10-27 10:48:49 +01:00
} else {
2013-09-22 06:56:31 +02:00
switch ( specifier [ 0 ] ) {
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " double " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " double " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " double " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( argInfo . typeToken - > str ( ) ! = " float " )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
break ;
}
}
}
done = true ;
break ;
case ' I ' :
2013-10-03 06:37:40 +02:00
if ( ( i + 1 ! = formatString . end ( ) & & * ( i + 1 ) = = ' 6 ' & &
i + 2 ! = formatString . end ( ) & & * ( i + 2 ) = = ' 4 ' ) | |
( i + 1 ! = formatString . end ( ) & & * ( i + 1 ) = = ' 3 ' & &
i + 2 ! = formatString . end ( ) & & * ( i + 2 ) = = ' 2 ' ) ) {
2013-09-22 06:56:31 +02:00
specifier + = * i + + ;
specifier + = * i + + ;
if ( ( i + 1 ) ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
} else {
2013-10-03 06:37:40 +02:00
if ( ( i + 1 ) ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
2013-09-22 06:56:31 +02:00
}
break ;
case ' h ' :
case ' l ' :
if ( i + 1 ! = formatString . end ( ) & & * ( i + 1 ) = = * i )
specifier + = * i + + ;
// fallthrough
case ' j ' :
case ' q ' :
case ' t ' :
case ' z ' :
case ' L ' :
// Expect an alphabetical character after these specifiers
if ( i ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
break ;
default :
done = true ;
break ;
2012-10-30 15:52:45 +01:00
}
2012-06-23 07:52:52 +02:00
}
2012-10-30 15:52:45 +01:00
} else if ( ! scan & & warning ) {
2013-07-21 08:35:01 +02:00
std : : string specifier ;
bool done = false ;
while ( ! done ) {
switch ( * i ) {
case ' s ' :
2013-09-03 05:50:19 +02:00
if ( argInfo . variableInfo & & argListTok - > type ( ) ! = Token : : eString & &
2013-10-27 10:48:49 +01:00
argInfo . isKnownType ( ) & & ! argInfo . isArrayOrPointer ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " char|wchar_t " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_s ( tok , numFormat , & argInfo ) ;
}
}
2013-07-21 08:35:01 +02:00
done = true ;
break ;
case ' n ' :
2013-09-03 05:50:19 +02:00
if ( ( argInfo . variableInfo & & argInfo . isKnownType ( ) & & ( ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " ) ) | | argListTok - > type ( ) = = Token : : eString )
2013-09-22 06:56:31 +02:00
invalidPrintfArgTypeError_n ( tok , numFormat , & argInfo ) ;
2013-07-21 08:35:01 +02:00
done = true ;
break ;
case ' c ' :
case ' x ' :
case ' X ' :
case ' o ' :
2013-08-10 12:33:55 +02:00
specifier + = * i ;
2013-09-24 06:43:03 +02:00
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2013-10-27 10:48:49 +01:00
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|short|long|int|char|wchar_t " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
} else {
2013-09-24 06:43:03 +02:00
switch ( specifier [ 0 ] ) {
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' j ' :
if ( ! ( argInfo . typeToken - > originalName ( ) = = " intmax_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' z ' :
if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' t ' :
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' I ' :
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2014-01-03 15:58:45 +01:00
} else if ( ! ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " WPARAM " | |
argInfo . typeToken - > originalName ( ) = = " UINT_PTR " | |
argInfo . typeToken - > originalName ( ) = = " LONG_PTR " | |
argInfo . typeToken - > originalName ( ) = = " LPARAM " | |
argInfo . typeToken - > originalName ( ) = = " LRESULT " ) )
2013-09-24 06:43:03 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
2013-09-29 15:25:18 +02:00
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|wchar_t|int " ) )
2013-09-24 06:43:03 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
}
2013-08-10 12:33:55 +02:00
}
2013-10-05 16:47:06 +02:00
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
2013-09-08 20:21:00 +02:00
// use %p on pointers and arrays
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2013-07-21 08:35:01 +02:00
}
done = true ;
break ;
case ' d ' :
case ' i ' :
2013-08-10 12:33:55 +02:00
specifier + = * i ;
2013-09-08 20:21:00 +02:00
if ( argInfo . typeToken - > type ( ) = = Token : : eString ) {
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
} else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2013-10-27 10:48:49 +01:00
} else if ( argInfo . typeToken - > isUnsigned ( ) & & ! Token : : Match ( argInfo . typeToken , " char|short " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int|long " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else {
2013-09-24 06:43:03 +02:00
switch ( specifier [ 0 ] ) {
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' j ' :
if ( argInfo . typeToken - > originalName ( ) ! = " intmax_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' t ' :
if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' I ' :
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int " ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " ptrdiff_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
}
2013-09-05 06:04:41 +02:00
}
2013-10-05 16:47:06 +02:00
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
2013-09-08 20:21:00 +02:00
// use %p on pointers and arrays
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2013-07-21 08:35:01 +02:00
}
done = true ;
break ;
case ' u ' :
2013-08-10 12:33:55 +02:00
specifier + = * i ;
2013-09-08 20:21:00 +02:00
if ( argInfo . typeToken - > type ( ) = = Token : : eString ) {
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
} else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2013-10-27 10:48:49 +01:00
} else if ( ! argInfo . typeToken - > isUnsigned ( ) & & argInfo . typeToken - > str ( ) ! = " bool " ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|long|int " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else {
2013-09-24 06:43:03 +02:00
switch ( specifier [ 0 ] ) {
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' j ' :
if ( argInfo . typeToken - > originalName ( ) ! = " uintmax_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' z ' :
if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' I ' :
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int " ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . typeToken - > originalName ( ) = = " size_t " | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
}
2013-07-21 08:35:01 +02:00
}
2013-10-05 16:47:06 +02:00
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2012-10-30 15:52:45 +01:00
}
2013-07-21 08:35:01 +02:00
done = true ;
break ;
case ' p ' :
2013-09-08 20:21:00 +02:00
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_p ( tok , numFormat , & argInfo ) ;
2013-09-08 20:21:00 +02:00
else if ( argInfo . isKnownType ( ) & & ! argInfo . isArrayOrPointer ( ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_p ( tok , numFormat , & argInfo ) ;
2013-07-21 08:35:01 +02:00
done = true ;
break ;
case ' e ' :
case ' E ' :
case ' f ' :
case ' g ' :
case ' G ' :
2013-08-24 07:25:50 +02:00
specifier + = * i ;
2013-09-08 20:21:00 +02:00
if ( argInfo . typeToken - > type ( ) = = Token : : eString )
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-10-27 10:48:49 +01:00
} else if ( ! Token : : Match ( argInfo . typeToken , " float|double " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ( specifier [ 0 ] = = ' L ' & & ( ! argInfo . typeToken - > isLong ( ) | | argInfo . typeToken - > str ( ) ! = " double " ) ) | |
( specifier [ 0 ] ! = ' L ' & & argInfo . typeToken - > isLong ( ) ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-10-05 16:47:06 +02:00
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
2013-09-08 20:21:00 +02:00
// use %p on pointers and arrays
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-09-08 20:21:00 +02:00
}
2013-07-21 08:35:01 +02:00
done = true ;
break ;
case ' h ' : // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
case ' l ' : // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
// If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
if ( i ! = formatString . end ( ) & & * ( i + 1 ) = = * i ) {
2013-07-22 08:28:29 +02:00
if ( i + 1 ! = formatString . end ( ) ) {
if ( ! isalpha ( * ( i + 2 ) ) ) {
std : : string modifier ;
modifier + = * i ;
modifier + = * ( i + 1 ) ;
invalidLengthModifierError ( tok , numFormat , modifier ) ;
done = true ;
} else {
specifier = * i + + ;
specifier + = * i + + ;
}
} else {
done = true ;
2013-07-21 08:35:01 +02:00
}
} else {
2013-07-22 08:28:29 +02:00
if ( i ! = formatString . end ( ) ) {
if ( ! isalpha ( * ( i + 1 ) ) ) {
std : : string modifier ;
modifier + = * i ;
invalidLengthModifierError ( tok , numFormat , modifier ) ;
done = true ;
} else {
specifier = * i + + ;
}
} else {
done = true ;
2013-07-21 08:35:01 +02:00
}
}
break ;
case ' I ' : // Microsoft extension: I for size_t and ptrdiff_t, I32 for __int32, and I64 for __int64
2013-08-10 12:37:31 +02:00
if ( ( * ( i + 1 ) = = ' 3 ' & & * ( i + 2 ) = = ' 2 ' ) | |
( * ( i + 1 ) = = ' 6 ' & & * ( i + 2 ) = = ' 4 ' ) ) {
specifier + = * i + + ;
specifier + = * i + + ;
2013-07-21 08:35:01 +02:00
}
2013-08-10 12:37:31 +02:00
// fallthrough
2013-07-21 08:35:01 +02:00
case ' j ' : // intmax_t or uintmax_t
case ' z ' : // size_t
case ' t ' : // ptrdiff_t
case ' L ' : // long double
// Expect an alphabetical character after these specifiers
2012-10-30 15:52:45 +01:00
if ( i ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
2013-08-10 12:37:31 +02:00
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
2013-07-22 08:28:29 +02:00
done = true ;
} else {
2013-08-10 12:37:31 +02:00
specifier + = * i + + ;
2012-10-30 15:52:45 +01:00
}
2013-07-21 08:35:01 +02:00
break ;
default :
done = true ;
break ;
2012-10-21 08:50:29 +02:00
}
}
2012-05-20 11:57:07 +02:00
}
}
2012-10-30 15:52:45 +01:00
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ; // Find next argument
}
2012-05-20 11:57:07 +02:00
}
}
2012-10-30 15:52:45 +01:00
// Count printf/scanf parameters..
unsigned int numFunction = 0 ;
while ( argListTok2 ) {
numFunction + + ;
argListTok2 = argListTok2 - > nextArgument ( ) ; // Find next argument
}
2013-07-28 16:13:16 +02:00
2013-07-28 15:00:28 +02:00
// Check that all parameter positions reference an actual parameter
2013-07-28 16:13:16 +02:00
for ( std : : set < unsigned int > : : const_iterator it = parameterPositionsUsed . begin ( ) ; it ! = parameterPositionsUsed . end ( ) ; + + it ) {
2013-07-28 20:33:49 +02:00
if ( ( ( * it = = 0 ) | | ( * it > numFormat ) ) & & _settings - > isEnabled ( " warning " ) )
2013-07-28 15:00:28 +02:00
wrongPrintfScanfPosixParameterPositionError ( tok , tok - > str ( ) , * it , numFormat ) ;
}
2012-05-20 11:57:07 +02:00
2012-10-30 15:52:45 +01:00
// Mismatching number of parameters => warning
2013-09-30 19:55:21 +02:00
if ( ( numFormat + numSecure ) ! = numFunction )
wrongPrintfScanfArgumentsError ( tok , tok - > originalName ( ) . empty ( ) ? tok - > str ( ) : tok - > originalName ( ) , numFormat + numSecure , numFunction ) ;
2012-10-30 15:52:45 +01:00
}
2012-05-20 11:57:07 +02:00
}
}
2013-08-24 07:25:50 +02:00
// We currently only support string literals, variables, and functions.
2013-08-24 22:34:52 +02:00
/// @todo add non-string literals, and generic expressions
2013-08-20 06:16:31 +02:00
2013-09-03 05:50:19 +02:00
CheckIO : : ArgumentInfo : : ArgumentInfo ( const Token * tok , const Settings * settings )
: variableInfo ( 0 )
, typeToken ( 0 )
, functionInfo ( 0 )
, element ( false )
2013-09-08 20:21:00 +02:00
, _template ( false )
2013-09-22 06:56:31 +02:00
, address ( false )
2013-09-03 05:50:19 +02:00
, tempToken ( 0 )
2013-08-20 06:16:31 +02:00
{
2013-08-23 05:35:57 +02:00
if ( tok ) {
if ( tok - > type ( ) = = Token : : eString ) {
2013-09-03 05:50:19 +02:00
typeToken = tok ;
return ;
2013-10-02 04:12:46 +02:00
} else if ( tok - > str ( ) = = " & " | | tok - > type ( ) = = Token : : eVariable | |
tok - > type ( ) = = Token : : eFunction | | Token : : Match ( tok , " %type% :: " ) | |
( Token : : Match ( tok , " static_cast|reinterpret_cast|const_cast < " ) & &
2014-03-14 16:26:37 +01:00
Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > ( " ) & &
2013-10-02 04:12:46 +02:00
Token : : Match ( tok - > linkAt ( 1 ) - > linkAt ( 1 ) , " ) ,|) " ) ) ) {
if ( Token : : Match ( tok , " static_cast|reinterpret_cast|const_cast " ) ) {
typeToken = tok - > tokAt ( 2 ) ;
if ( typeToken - > str ( ) = = " const " )
typeToken = typeToken - > next ( ) ;
return ;
}
2013-09-22 06:56:31 +02:00
if ( tok - > str ( ) = = " & " ) {
address = true ;
tok = tok - > next ( ) ;
}
2013-08-24 22:34:52 +02:00
while ( Token : : Match ( tok , " %type% :: " ) )
tok = tok - > tokAt ( 2 ) ;
if ( ! tok | | ! ( tok - > type ( ) = = Token : : eVariable | | tok - > type ( ) = = Token : : eFunction ) )
2013-09-03 05:50:19 +02:00
return ;
2014-02-16 11:47:52 +01:00
const Token * varTok = nullptr ;
2013-08-27 05:46:09 +02:00
const Token * tok1 = tok - > next ( ) ;
for ( ; tok1 ; tok1 = tok1 - > next ( ) ) {
2013-08-23 05:35:57 +02:00
if ( tok1 - > str ( ) = = " , " | | tok1 - > str ( ) = = " ) " ) {
2013-08-28 05:57:40 +02:00
if ( tok1 - > previous ( ) - > str ( ) = = " ] " ) {
2013-08-23 05:35:57 +02:00
varTok = tok1 - > linkAt ( - 1 ) - > previous ( ) ;
2013-08-28 05:57:40 +02:00
if ( varTok - > str ( ) = = " ) " & & varTok - > link ( ) - > previous ( ) - > type ( ) = = Token : : eFunction ) {
const Function * function = varTok - > link ( ) - > previous ( ) - > function ( ) ;
2013-08-31 18:58:55 +02:00
if ( function & & function - > retDef ) {
2013-09-03 05:50:19 +02:00
typeToken = function - > retDef ;
2013-09-22 06:56:31 +02:00
if ( typeToken - > str ( ) = = " const " )
typeToken = typeToken - > next ( ) ;
2013-09-03 05:50:19 +02:00
functionInfo = function ;
2013-08-28 05:57:40 +02:00
element = true ;
2013-09-03 05:50:19 +02:00
return ;
2013-08-31 18:58:55 +02:00
} else
2013-09-03 05:50:19 +02:00
return ;
2013-08-28 05:57:40 +02:00
}
} else if ( tok1 - > previous ( ) - > str ( ) = = " ) " & & tok1 - > linkAt ( - 1 ) - > previous ( ) - > type ( ) = = Token : : eFunction ) {
2013-08-24 07:25:50 +02:00
const Function * function = tok1 - > linkAt ( - 1 ) - > previous ( ) - > function ( ) ;
2013-08-31 18:58:55 +02:00
if ( function & & function - > retDef ) {
2013-09-03 05:50:19 +02:00
typeToken = function - > retDef ;
2013-09-22 06:56:31 +02:00
if ( typeToken - > str ( ) = = " const " )
typeToken = typeToken - > next ( ) ;
2013-09-03 05:50:19 +02:00
functionInfo = function ;
2013-08-27 05:46:09 +02:00
element = false ;
2013-09-03 05:50:19 +02:00
return ;
2013-08-31 18:58:55 +02:00
} else
2013-09-03 05:50:19 +02:00
return ;
2013-08-24 07:25:50 +02:00
} else
2013-08-23 05:35:57 +02:00
varTok = tok1 - > previous ( ) ;
break ;
} else if ( tok1 - > str ( ) = = " ( " | | tok1 - > str ( ) = = " { " || tok1->str() == " [ " )
tok1 = tok1 - > link ( ) ;
else if ( tok1 - > str ( ) = = " < " & & tok1 - > link ( ) )
tok1 = tok1 - > link ( ) ;
2013-09-03 05:50:19 +02:00
// check for some common well known functions
2013-09-08 20:21:00 +02:00
else if ( ( Token : : Match ( tok1 - > previous ( ) , " %var% . size|empty|c_str ( ) " ) & & isStdContainer ( tok1 - > previous ( ) ) ) | |
( Token : : Match ( tok1 - > previous ( ) , " ] . size|empty|c_str ( ) " ) & & Token : : Match ( tok1 - > previous ( ) - > link ( ) - > previous ( ) , " %var% " ) & & isStdContainer ( tok1 - > previous ( ) - > link ( ) - > previous ( ) ) ) ) {
2013-09-03 05:50:19 +02:00
tempToken = new Token ( 0 ) ;
tempToken - > fileIndex ( tok1 - > fileIndex ( ) ) ;
tempToken - > linenr ( tok1 - > linenr ( ) ) ;
if ( tok1 - > next ( ) - > str ( ) = = " size " ) {
// size_t is platform dependent
if ( settings - > sizeof_size_t = = 8 ) {
tempToken - > str ( " long " ) ;
if ( settings - > sizeof_long ! = 8 )
tempToken - > isLong ( true ) ;
} else if ( settings - > sizeof_size_t = = 4 & & settings - > sizeof_long = = 4 )
tempToken - > str ( " long " ) ;
else if ( settings - > sizeof_size_t = = 4 )
tempToken - > str ( " int " ) ;
tempToken - > originalName ( " size_t " ) ;
tempToken - > isUnsigned ( true ) ;
} else if ( tok1 - > next ( ) - > str ( ) = = " empty " ) {
tempToken - > str ( " bool " ) ;
} else if ( tok1 - > next ( ) - > str ( ) = = " c_str " ) {
tempToken - > str ( " const " ) ;
tempToken - > insertToken ( " * " ) ;
2013-09-08 20:21:00 +02:00
if ( typeToken - > strAt ( 2 ) = = " string " )
2013-09-03 05:50:19 +02:00
tempToken - > insertToken ( " char " ) ;
else
tempToken - > insertToken ( " wchar_t " ) ;
}
typeToken = tempToken ;
2013-11-08 12:44:05 +01:00
return ;
}
// check for std::vector::at() and std::string::at()
else if ( Token : : Match ( tok1 - > previous ( ) , " %var% . at ( " ) & &
Token : : Match ( tok1 - > linkAt ( 2 ) , " ) [,)] " ) ) {
varTok = tok1 - > previous ( ) ;
variableInfo = varTok - > variable ( ) ;
2013-11-23 08:40:35 +01:00
if ( ! variableInfo | | ! isStdVectorOrString ( ) ) {
2013-11-08 12:44:05 +01:00
variableInfo = 0 ;
typeToken = 0 ;
}
2013-09-03 05:50:19 +02:00
return ;
} else if ( ! ( tok1 - > str ( ) = = " . " | | tok1 - > type ( ) = = Token : : eVariable | | tok1 - > type ( ) = = Token : : eFunction ) )
return ;
2013-08-23 05:35:57 +02:00
}
2013-08-20 06:16:31 +02:00
2013-08-23 05:35:57 +02:00
if ( varTok ) {
2013-09-03 05:50:19 +02:00
variableInfo = varTok - > variable ( ) ;
2013-08-27 05:46:09 +02:00
element = tok1 - > previous ( ) - > str ( ) = = " ] " ;
2013-08-30 05:41:59 +02:00
// look for std::vector operator [] and use template type as return type
if ( variableInfo ) {
2013-09-08 20:21:00 +02:00
if ( element & & isStdVectorOrString ( ) ) { // isStdVectorOrString sets type token if true
2013-08-30 05:41:59 +02:00
element = false ; // not really an array element
} else
2013-09-03 05:50:19 +02:00
typeToken = variableInfo - > typeStartToken ( ) ;
}
2013-08-30 05:41:59 +02:00
2013-09-03 05:50:19 +02:00
return ;
2013-08-23 05:35:57 +02:00
}
}
2013-08-20 06:16:31 +02:00
}
2013-09-03 05:50:19 +02:00
}
2013-11-01 05:42:37 +01:00
CheckIO : : ArgumentInfo : : ~ ArgumentInfo ( )
{
if ( tempToken ) {
while ( tempToken - > next ( ) )
tempToken - > deleteNext ( ) ;
delete tempToken ;
}
}
2013-09-08 20:21:00 +02:00
bool CheckIO : : ArgumentInfo : : isStdVectorOrString ( )
2013-09-07 07:20:06 +02:00
{
2014-01-30 05:26:48 +01:00
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char * const stl_vector [ ] = {
" array " , " vector "
} ;
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char * const stl_string [ ] = {
" string " , " u16string " , " u32string " , " wstring "
} ;
if ( variableInfo - > isStlType ( stl_vector ) ) {
2013-09-07 07:20:06 +02:00
typeToken = variableInfo - > typeStartToken ( ) - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
_template = true ;
return true ;
2014-01-30 05:26:48 +01:00
} else if ( variableInfo - > isStlType ( stl_string ) ) {
2013-09-08 20:21:00 +02:00
tempToken = new Token ( 0 ) ;
tempToken - > fileIndex ( variableInfo - > typeStartToken ( ) - > fileIndex ( ) ) ;
tempToken - > linenr ( variableInfo - > typeStartToken ( ) - > linenr ( ) ) ;
if ( variableInfo - > typeStartToken ( ) - > strAt ( 2 ) = = " string " )
tempToken - > str ( " char " ) ;
else
tempToken - > str ( " wchar_t " ) ;
typeToken = tempToken ;
2013-09-07 07:20:06 +02:00
return true ;
} else if ( variableInfo - > type ( ) & & ! variableInfo - > type ( ) - > derivedFrom . empty ( ) ) {
for ( std : : size_t i = 0 , e = variableInfo - > type ( ) - > derivedFrom . size ( ) ; i ! = e ; + + i ) {
if ( Token : : Match ( variableInfo - > type ( ) - > derivedFrom [ i ] . nameTok , " std :: vector|array < " ) ) {
typeToken = variableInfo - > type ( ) - > derivedFrom [ i ] . nameTok - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
_template = true ;
return true ;
} else if ( Token : : Match ( variableInfo - > type ( ) - > derivedFrom [ i ] . nameTok , " std :: string|wstring " ) ) {
tempToken = new Token ( 0 ) ;
tempToken - > fileIndex ( variableInfo - > typeStartToken ( ) - > fileIndex ( ) ) ;
tempToken - > linenr ( variableInfo - > typeStartToken ( ) - > linenr ( ) ) ;
if ( variableInfo - > type ( ) - > derivedFrom [ i ] . nameTok - > strAt ( 2 ) = = " string " )
tempToken - > str ( " char " ) ;
else
tempToken - > str ( " wchar_t " ) ;
typeToken = tempToken ;
2013-09-07 07:20:06 +02:00
return true ;
}
}
}
return false ;
}
bool CheckIO : : ArgumentInfo : : isStdContainer ( const Token * tok )
{
2014-01-30 05:26:48 +01:00
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char * const stl_container [ ] = {
" array " , " bitset " , " deque " , " forward_list " ,
" hash_map " , " hash_multimap " , " hash_set " ,
" list " , " map " , " multimap " , " multiset " ,
" priority_queue " , " queue " , " set " , " stack " ,
" unordered_map " , " unordered_multimap " , " unordered_multiset " , " unordered_set " ,
" vector "
} ;
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char * const stl_string [ ] = {
" string " , " u16string " , " u32string " , " wstring "
} ;
2013-09-07 07:20:06 +02:00
if ( tok & & tok - > variable ( ) ) {
2014-01-30 05:26:48 +01:00
if ( tok - > variable ( ) - > isStlType ( stl_container ) ) {
2013-09-08 20:21:00 +02:00
typeToken = tok - > variable ( ) - > typeStartToken ( ) - > tokAt ( 4 ) ;
return true ;
2014-01-30 05:26:48 +01:00
} else if ( tok - > variable ( ) - > isStlType ( stl_string ) ) {
2013-09-08 20:21:00 +02:00
typeToken = tok - > variable ( ) - > typeStartToken ( ) ;
2013-09-07 07:20:06 +02:00
return true ;
} else if ( tok - > variable ( ) - > type ( ) & & ! tok - > variable ( ) - > type ( ) - > derivedFrom . empty ( ) ) {
for ( std : : size_t i = 0 , e = tok - > variable ( ) - > type ( ) - > derivedFrom . size ( ) ; i ! = e ; + + i ) {
2013-09-08 20:21:00 +02:00
if ( Token : : Match ( tok - > variable ( ) - > type ( ) - > derivedFrom [ i ] . nameTok , " std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset < " ) ) {
typeToken = tok - > variable ( ) - > type ( ) - > derivedFrom [ i ] . nameTok - > tokAt ( 4 ) ;
return true ;
} else if ( Token : : Match ( tok - > variable ( ) - > type ( ) - > derivedFrom [ i ] . nameTok , " std :: string|wstring " ) ) {
typeToken = tok - > variable ( ) - > type ( ) - > derivedFrom [ i ] . nameTok ;
2013-09-07 07:20:06 +02:00
return true ;
}
}
}
}
return false ;
}
2013-09-08 20:21:00 +02:00
bool CheckIO : : ArgumentInfo : : isArrayOrPointer ( ) const
{
2013-09-22 06:56:31 +02:00
if ( address )
return true ;
else if ( variableInfo & & ! _template ) {
2013-09-08 20:21:00 +02:00
return variableInfo - > isArrayOrPointer ( ) ;
} else {
const Token * tok = typeToken ;
while ( tok & & Token : : Match ( tok , " const|struct " ) )
tok = tok - > next ( ) ;
if ( tok & & tok - > strAt ( 1 ) = = " * " )
return true ;
}
return false ;
}
2013-09-03 05:50:19 +02:00
bool CheckIO : : ArgumentInfo : : isComplexType ( ) const
{
if ( variableInfo - > type ( ) )
return ( true ) ;
static std : : set < std : : string > knownTypes ;
if ( knownTypes . empty ( ) ) {
knownTypes . insert ( " string " ) ;
knownTypes . insert ( " wstring " ) ;
}
const Token * varTypeTok = typeToken ;
if ( varTypeTok - > str ( ) = = " std " )
varTypeTok = varTypeTok - > tokAt ( 2 ) ;
return ( ( knownTypes . find ( varTypeTok - > str ( ) ) ! = knownTypes . end ( ) | | ( varTypeTok - > strAt ( 1 ) = = " < " & & varTypeTok - > linkAt ( 1 ) & & varTypeTok - > linkAt ( 1 ) - > strAt ( 1 ) ! = " :: " ) ) & & ! variableInfo - > isArrayOrPointer ( ) ) ;
}
bool CheckIO : : ArgumentInfo : : isKnownType ( ) const
{
if ( variableInfo )
return ( typeToken - > isStandardType ( ) | | typeToken - > next ( ) - > isStandardType ( ) | | isComplexType ( ) ) ;
else if ( functionInfo )
return ( typeToken - > isStandardType ( ) | | functionInfo - > retType ) ;
2013-08-20 06:16:31 +02:00
2013-09-24 06:43:03 +02:00
return typeToken - > isStandardType ( ) | | Token : : Match ( typeToken , " std :: string|wstring " ) ;
2013-08-20 06:16:31 +02:00
}
2012-05-20 11:57:07 +02:00
void CheckIO : : wrongPrintfScanfArgumentsError ( const Token * tok ,
const std : : string & functionName ,
unsigned int numFormat ,
unsigned int numFunction )
{
Severity : : SeverityType severity = numFormat > numFunction ? Severity : : error : Severity : : warning ;
if ( severity ! = Severity : : error & & ! _settings - > isEnabled ( " style " ) )
return ;
std : : ostringstream errmsg ;
errmsg < < functionName
2013-09-30 19:55:21 +02:00
< < " format string requires "
2012-05-20 11:57:07 +02:00
< < numFormat
2013-09-30 19:55:21 +02:00
< < " parameter " < < ( numFormat ! = 1 ? " s " : " " ) < < " but "
2012-05-20 11:57:07 +02:00
< < ( numFormat > numFunction ? " only " : " " )
< < numFunction
2013-09-30 19:55:21 +02:00
< < ( numFunction ! = 1 ? " are " : " is " )
< < " given. " ;
2012-05-20 11:57:07 +02:00
reportError ( tok , severity , " wrongPrintfScanfArgNum " , errmsg . str ( ) ) ;
}
2013-07-28 15:00:28 +02:00
void CheckIO : : wrongPrintfScanfPosixParameterPositionError ( const Token * tok , const std : : string & functionName ,
2013-07-28 16:13:16 +02:00
unsigned int index , unsigned int numFunction )
2013-07-28 15:00:28 +02:00
{
std : : ostringstream errmsg ;
errmsg < < functionName < < " : " ;
2013-07-28 16:13:16 +02:00
if ( index = = 0 ) {
2013-07-28 15:00:28 +02:00
errmsg < < " parameter positions start at 1, not 0 " ;
} else {
errmsg < < " referencing parameter " < < index < < " while " < < numFunction < < " arguments given " ;
}
2013-07-28 20:33:49 +02:00
reportError ( tok , Severity : : warning , " wrongPrintfScanfParameterPositionError " , errmsg . str ( ) ) ;
2013-07-28 15:00:28 +02:00
}
2013-09-22 06:56:31 +02:00
void CheckIO : : invalidScanfArgTypeError_s ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-09-22 06:56:31 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires a \' " ;
if ( specifier [ 0 ] = = ' s ' )
errmsg < < " char " ;
else if ( specifier [ 0 ] = = ' S ' )
errmsg < < " wchar_t " ;
errmsg < < " * \' but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
reportError ( tok , Severity : : warning , " invalidScanfArgType_s " , errmsg . str ( ) ) ;
2012-05-20 11:57:07 +02:00
}
2013-09-22 06:56:31 +02:00
void CheckIO : : invalidScanfArgTypeError_int ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo , bool isUnsigned )
{
std : : ostringstream errmsg ;
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires \' " ;
if ( specifier [ 0 ] = = ' h ' ) {
if ( specifier [ 1 ] = = ' h ' )
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " char " ;
else
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " short " ;
} else if ( specifier [ 0 ] = = ' l ' ) {
if ( specifier [ 1 ] = = ' l ' )
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " long long " ;
else
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " long " ;
2013-10-03 06:37:40 +02:00
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " __int32 " ;
} else if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
2013-09-22 06:56:31 +02:00
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " __int64 " ;
2013-10-03 06:37:40 +02:00
} else if ( specifier [ 0 ] = = ' I ' ) {
errmsg < < ( isUnsigned ? " size_t " : " ptrdiff_t " ) ;
2013-09-22 06:56:31 +02:00
} else if ( specifier [ 0 ] = = ' j ' ) {
if ( isUnsigned )
errmsg < < " uintmax_t " ;
else
errmsg < < " intmax_t " ;
} else if ( specifier [ 0 ] = = ' z ' ) {
2014-01-14 06:09:13 +01:00
if ( specifier [ 1 ] = = ' d ' )
errmsg < < " ptrdiff_t " ;
else
errmsg < < " size_t " ;
2013-09-22 06:56:31 +02:00
} else if ( specifier [ 0 ] = = ' t ' ) {
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " ptrdiff_t " ;
} else if ( specifier [ 0 ] = = ' L ' ) {
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " long long " ;
} else {
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " int " ;
}
errmsg < < " * \' but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
reportError ( tok , Severity : : warning , " invalidScanfArgType_int " , errmsg . str ( ) ) ;
}
void CheckIO : : invalidScanfArgTypeError_float ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
{
std : : ostringstream errmsg ;
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires \' " ;
if ( specifier [ 0 ] = = ' l ' & & specifier [ 1 ] ! = ' l ' )
errmsg < < " double " ;
else if ( specifier [ 0 ] = = ' L ' )
errmsg < < " long double " ;
else
errmsg < < " float " ;
errmsg < < " * \' but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
reportError ( tok , Severity : : warning , " invalidScanfArgType_float " , errmsg . str ( ) ) ;
}
2013-10-27 10:48:49 +01:00
void CheckIO : : invalidPrintfArgTypeError_s ( const Token * tok , unsigned int numFormat , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-10-27 10:48:49 +01:00
errmsg < < " %s in format string (no. " < < numFormat < < " ) requires \' char * \' but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-05-20 11:57:07 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_s " , errmsg . str ( ) ) ;
}
2013-09-22 06:56:31 +02:00
void CheckIO : : invalidPrintfArgTypeError_n ( const Token * tok , unsigned int numFormat , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-09-22 06:56:31 +02:00
errmsg < < " %n in format string (no. " < < numFormat < < " ) requires \' int * \' but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-05-20 11:57:07 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_n " , errmsg . str ( ) ) ;
}
2013-09-05 01:46:58 +02:00
void CheckIO : : invalidPrintfArgTypeError_p ( const Token * tok , unsigned int numFormat , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-09-05 01:46:58 +02:00
errmsg < < " %p in format string (no. " < < numFormat < < " ) requires an address but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-05-20 11:57:07 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_p " , errmsg . str ( ) ) ;
}
2013-09-29 10:42:47 +02:00
static void printfFormatType ( std : : ostream & os , const std : : string & specifier , bool isUnsigned )
{
os < < " \' " ;
if ( specifier [ 0 ] = = ' l ' ) {
if ( specifier [ 1 ] = = ' l ' )
os < < ( isUnsigned ? " unsigned " : " " ) < < " long long " ;
else
os < < ( isUnsigned ? " unsigned " : " " ) < < " long " ;
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
os < < ( isUnsigned ? " unsigned " : " " ) < < " __int32 " ;
} else if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
os < < ( isUnsigned ? " unsigned " : " " ) < < " __int64 " ;
} else if ( specifier [ 0 ] = = ' I ' ) {
os < < ( isUnsigned ? " size_t " : " ptrdiff_t " ) ;
} else if ( specifier [ 0 ] = = ' j ' ) {
if ( isUnsigned )
os < < " uintmax_t " ;
else
os < < " intmax_t " ;
} else if ( specifier [ 0 ] = = ' z ' ) {
if ( specifier [ 1 ] = = ' d ' )
os < < " ssize_t " ;
else
os < < " size_t " ;
} else if ( specifier [ 0 ] = = ' t ' ) {
os < < ( isUnsigned ? " unsigned " : " " ) < < " ptrdiff_t " ;
} else if ( specifier [ 0 ] = = ' L ' ) {
os < < ( isUnsigned ? " unsigned " : " " ) < < " long long " ;
} else {
os < < ( isUnsigned ? " unsigned " : " " ) < < " int " ;
}
os < < " \' " ;
}
2013-09-05 01:46:58 +02:00
void CheckIO : : invalidPrintfArgTypeError_int ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-09-29 10:42:47 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires " ;
printfFormatType ( errmsg , specifier , true ) ;
errmsg < < " but the argument type is " ;
2013-09-05 01:46:58 +02:00
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-05-20 11:57:07 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_int " , errmsg . str ( ) ) ;
}
2013-09-05 01:46:58 +02:00
void CheckIO : : invalidPrintfArgTypeError_uint ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
2012-07-11 19:46:35 +02:00
{
std : : ostringstream errmsg ;
2013-09-29 10:42:47 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires " ;
printfFormatType ( errmsg , specifier , true ) ;
errmsg < < " but the argument type is " ;
2013-09-05 01:46:58 +02:00
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-07-11 19:46:35 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_uint " , errmsg . str ( ) ) ;
}
2013-09-29 10:42:47 +02:00
2013-09-05 01:46:58 +02:00
void CheckIO : : invalidPrintfArgTypeError_sint ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
2012-07-11 19:46:35 +02:00
{
std : : ostringstream errmsg ;
2013-09-29 10:42:47 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires " ;
printfFormatType ( errmsg , specifier , false ) ;
errmsg < < " but the argument type is " ;
2013-09-05 01:46:58 +02:00
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-07-11 19:46:35 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_sint " , errmsg . str ( ) ) ;
}
2013-09-05 01:46:58 +02:00
void CheckIO : : invalidPrintfArgTypeError_float ( const Token * tok , unsigned int numFormat , const std : : string & specifier , const ArgumentInfo * argInfo )
2012-05-20 11:57:07 +02:00
{
std : : ostringstream errmsg ;
2013-09-29 10:42:47 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires \' " ;
2013-09-15 16:38:45 +02:00
if ( specifier [ 0 ] = = ' L ' )
errmsg < < " long " ;
errmsg < < " double \' but the argument type is " ;
2013-09-05 01:46:58 +02:00
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
reportError ( tok , Severity : : warning , " invalidPrintfArgType_float " , errmsg . str ( ) ) ;
}
void CheckIO : : argumentType ( std : : ostream & os , const ArgumentInfo * argInfo )
{
if ( argInfo ) {
os < < " \' " ;
const Token * type = argInfo - > typeToken ;
2013-08-31 06:26:39 +02:00
if ( type - > type ( ) = = Token : : eString ) {
if ( type - > isLong ( ) )
2013-09-05 01:46:58 +02:00
os < < " const wchar_t * " ;
2013-08-31 06:26:39 +02:00
else
2013-09-05 01:46:58 +02:00
os < < " const char * " ;
2013-08-31 06:26:39 +02:00
} else {
if ( type - > originalName ( ) . empty ( ) ) {
2013-09-22 06:56:31 +02:00
if ( type - > strAt ( - 1 ) = = " const " )
os < < " const " ;
2013-09-08 20:21:00 +02:00
while ( Token : : Match ( type , " const|struct " ) ) {
os < < type - > str ( ) < < " " ;
2013-09-03 05:50:19 +02:00
type = type - > next ( ) ;
}
2013-10-27 10:48:49 +01:00
while ( Token : : Match ( type , " %any% :: " ) ) {
os < < type - > str ( ) < < " :: " ;
type = type - > tokAt ( 2 ) ;
}
2013-09-05 01:46:58 +02:00
type - > stringify ( os , false , true ) ;
2013-10-05 16:47:06 +02:00
if ( type - > strAt ( 1 ) = = " * " & & ! argInfo - > element )
2013-09-08 20:21:00 +02:00
os < < " * " ;
else if ( argInfo - > variableInfo & & ! argInfo - > element & & argInfo - > variableInfo - > isArray ( ) )
2013-09-05 01:46:58 +02:00
os < < " * " ;
2013-10-27 10:48:49 +01:00
else if ( type - > strAt ( 1 ) = = " * " & & argInfo - > variableInfo & & argInfo - > element & & argInfo - > variableInfo - > isArray ( ) )
os < < " * " ;
2013-09-22 06:56:31 +02:00
if ( argInfo - > address )
os < < " * " ;
2013-08-31 06:26:39 +02:00
} else {
if ( ( type - > originalName ( ) = = " __int64 " | | type - > originalName ( ) = = " __int32 " ) & & type - > isUnsigned ( ) )
2013-09-05 01:46:58 +02:00
os < < " unsigned " ;
2013-09-22 06:56:31 +02:00
os < < type - > originalName ( ) ;
if ( type - > strAt ( 1 ) = = " * " | | argInfo - > address )
os < < " * " ;
os < < " {aka " ;
2013-09-05 01:46:58 +02:00
type - > stringify ( os , false , true ) ;
2013-09-22 06:56:31 +02:00
if ( type - > strAt ( 1 ) = = " * " | | argInfo - > address )
2013-09-05 01:46:58 +02:00
os < < " * " ;
os < < " } " ;
2013-08-31 06:26:39 +02:00
}
}
2013-09-05 01:46:58 +02:00
os < < " \' " ;
2013-08-31 06:26:39 +02:00
} else
2013-09-05 01:46:58 +02:00
os < < " Unknown " ;
2012-05-20 11:57:07 +02:00
}
2013-09-05 01:46:58 +02:00
2013-07-21 08:35:01 +02:00
void CheckIO : : invalidLengthModifierError ( const Token * tok , unsigned int numFormat , const std : : string & modifier )
2012-10-21 08:50:29 +02:00
{
std : : ostringstream errmsg ;
errmsg < < " ' " < < modifier < < " ' in format string (no. " < < numFormat < < " ) is a length modifier and cannot be used without a conversion specifier. " ;
reportError ( tok , Severity : : warning , " invalidLengthModifierError " , errmsg . str ( ) ) ;
}
2012-07-13 19:36:58 +02:00
void CheckIO : : invalidScanfFormatWidthError ( const Token * tok , unsigned int numFormat , int width , const Variable * var )
2012-06-23 07:52:52 +02:00
{
std : : ostringstream errmsg ;
Severity : : SeverityType severity = Severity : : warning ;
bool inconclusive = false ;
if ( var ) {
if ( var - > dimension ( 0 ) > width ) {
if ( ! _settings - > inconclusive )
return ;
inconclusive = true ;
2012-07-13 19:36:58 +02:00
errmsg < < " Width " < < width < < " given in format string (no. " < < numFormat < < " ) is smaller than destination buffer "
< < " ' " < < var - > name ( ) < < " [ " < < var - > dimension ( 0 ) < < " ]'. " ;
2012-06-23 07:52:52 +02:00
} else {
2012-07-13 19:36:58 +02:00
errmsg < < " Width " < < width < < " given in format string (no. " < < numFormat < < " ) is larger than destination buffer ' "
< < var - > name ( ) < < " [ " < < var - > dimension ( 0 ) < < " ]', use % " < < ( var - > dimension ( 0 ) - 1 ) < < " s to prevent overflowing it. " ;
2012-06-23 07:52:52 +02:00
severity = Severity : : error ;
}
} else
2012-07-13 19:36:58 +02:00
errmsg < < " Width " < < width < < " given in format string (no. " < < numFormat < < " ) doesn't match destination buffer. " ;
2012-06-23 07:52:52 +02:00
2012-09-10 16:23:00 +02:00
if ( severity = = Severity : : error | | _settings - > isEnabled ( " style " ) )
reportError ( tok , severity , " invalidScanfFormatWidth " , errmsg . str ( ) , inconclusive ) ;
2012-06-23 07:52:52 +02:00
}