2012-05-20 11:57:07 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2013-01-01 17:29:08 +01:00
* Copyright ( C ) 2007 - 2013 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
//---------------------------------------------------------------------------
2012-05-22 14:30:22 +02:00
enum OpenMode { CLOSED , READ_MODE , WRITE_MODE , RW_MODE , UNKNOWN } ;
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 ;
return UNKNOWN ;
}
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 ;
Filepointer ( OpenMode mode_ = UNKNOWN )
: mode ( mode_ ) , mode_indent ( 0 ) , lastOperation ( NONE ) , op_indent ( 0 ) {
}
} ;
2012-05-22 14:30:22 +02:00
void CheckIO : : checkFileUsage ( )
{
static const char * _whitelist [ ] = {
" clearerr " , " feof " , " ferror " , " fgetpos " , " ftell " , " setbuf " , " setvbuf " , " ungetc "
} ;
static const std : : set < std : : string > whitelist ( _whitelist , _whitelist + sizeof ( _whitelist ) / sizeof ( * _whitelist ) ) ;
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"
2013-07-20 12:31:04 +02:00
filepointers . insert ( std : : make_pair ( var - > declarationId ( ) , Filepointer ( UNKNOWN ) ) ) ;
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 {
2013-07-20 12:31:04 +02:00
filepointers . insert ( std : : make_pair ( var - > declarationId ( ) , Filepointer ( UNKNOWN ) ) ) ;
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 ;
i - > second . mode = UNKNOWN ;
}
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 ;
i - > second . mode = UNKNOWN ;
i - > second . op_indent = 0 ;
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
2012-10-30 15:52:45 +01:00
} else if ( tok - > varId ( ) & & Token : : Match ( tok , " %var% = " ) & & ( tok - > strAt ( 2 ) ! = " fopen " & & tok - > strAt ( 2 ) ! = " freopen " & & tok - > strAt ( 2 ) ! = " tmpfile " ) ) {
std : : map < unsigned int , Filepointer > : : iterator i = filepointers . find ( tok - > varId ( ) ) ;
if ( i ! = filepointers . end ( ) ) {
i - > second . mode = UNKNOWN ;
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 ;
if ( ( tok - > str ( ) = = " fopen " | | tok - > str ( ) = = " freopen " | | tok - > str ( ) = = " tmpfile " ) & & tok - > strAt ( - 1 ) = = " = " ) {
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 ;
} else if ( tok - > str ( ) = = " rewind " | | tok - > str ( ) = = " fseek " | | tok - > str ( ) = = " fsetpos " | | tok - > str ( ) = = " fflush " ) {
if ( Token : : simpleMatch ( tok , " fflush ( stdin ) " ) )
fflushOnInputStreamError ( tok , tok - > strAt ( 2 ) ) ;
else {
fileTok = tok - > tokAt ( 2 ) ;
operation = Filepointer : : POSITIONING ;
}
} else if ( tok - > str ( ) = = " fgetc " | | tok - > str ( ) = = " fgets " | | tok - > str ( ) = = " fread " | | tok - > str ( ) = = " fscanf " | | tok - > str ( ) = = " getc " ) {
if ( tok - > str ( ) = = " fscanf " )
fileTok = tok - > tokAt ( 2 ) ;
else
fileTok = tok - > linkAt ( 1 ) - > previous ( ) ;
operation = Filepointer : : READ ;
} else if ( tok - > str ( ) = = " fputc " | | tok - > str ( ) = = " fputs " | | tok - > str ( ) = = " fwrite " | | tok - > str ( ) = = " fprintf " | | tok - > str ( ) = = " putcc " ) {
if ( tok - > str ( ) = = " fprintf " )
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 ) ;
2012-10-30 15:52:45 +01:00
if ( tok - > str ( ) = = " ungetc " & & fileTok )
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
filepointers . insert ( std : : make_pair ( fileTok - > varId ( ) , Filepointer ( UNKNOWN ) ) ) ;
}
Filepointer & f = filepointers [ fileTok - > varId ( ) ] ;
switch ( operation ) {
case Filepointer : : OPEN :
f . mode = getMode ( mode ) ;
f . mode_indent = indent ;
break ;
case Filepointer : : POSITIONING :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
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 :
f . mode = UNKNOWN ;
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 ;
i - > second . mode = UNKNOWN ;
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. " ) ;
}
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
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 ( ) ) {
const Token * formatToken = 0 ;
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
2012-10-30 15:52:45 +01:00
// scan the string backwards, so we dont need to keep states
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 ) ;
else if ( formatstr [ i ] ! = ' n ' & & formatstr [ i ] ! = ' c ' & & _settings - > platformType ! = Settings : : Win32A & & _settings - > platformType ! = Settings : : Win32W & & _settings - > platformType ! = Settings : : Win64 & & _settings - > isEnabled ( " portability " ) )
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
//---------------------------------------------------------------------------
void CheckIO : : checkWrongPrintfScanfArguments ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2013-03-03 11:41:59 +01:00
bool warning = _settings - > isEnabled ( " warning " ) ;
2013-09-26 16:20:01 +02:00
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
std : : string formatString ;
2013-07-22 20:21:45 +02:00
if ( Token : : Match ( tok - > next ( ) , " ( %any% " ) ) {
const Token * arg = tok - > tokAt ( 2 ) ;
int argnr = 1 ;
while ( arg ) {
if ( Token : : Match ( arg , " %str% [,)] " ) & & _settings - > library . isargformatstr ( tok - > str ( ) , argnr ) ) {
formatString = arg - > str ( ) ;
if ( arg - > strAt ( 1 ) = = " , " )
argListTok = arg - > tokAt ( 2 ) ;
else
argListTok = 0 ;
break ;
}
arg = arg - > nextArgument ( ) ;
argnr + + ;
}
}
2013-07-24 11:20:28 +02:00
if ( ! formatString . empty ( ) ) {
/* formatstring found in library */
2013-09-26 16:20:01 +02:00
} else if ( Token : : Match ( tok , " printf|scanf|wprintf|wscanf ( %str% " ) | |
( windows & & ( Token : : Match ( tok , " Format|AppendFormat ( %str% " ) & &
Token : : Match ( tok - > tokAt ( - 2 ) , " %var% . " ) & & tok - > tokAt ( - 2 ) - > variable ( ) & &
tok - > tokAt ( - 2 ) - > variable ( ) - > typeStartToken ( ) - > str ( ) = = " CString " ) ) ) {
2012-10-30 15:52:45 +01:00
formatString = tok - > strAt ( 2 ) ;
if ( tok - > strAt ( 3 ) = = " , " ) {
argListTok = tok - > tokAt ( 4 ) ;
} else if ( tok - > strAt ( 3 ) = = " ) " ) {
argListTok = 0 ;
} else {
continue ;
}
2013-05-14 11:06:16 +02:00
} else if ( Token : : Match ( tok , " sprintf|fprintf|sscanf|fscanf|swscanf|fwprintf|fwscanf ( %any% " ) | | ( Token : : simpleMatch ( tok , " swprintf ( " ) & & Token : : Match ( tok - > tokAt ( 2 ) - > nextArgument ( ) , " %str% " ) ) ) {
2012-10-30 15:52:45 +01:00
const Token * formatStringTok = tok - > tokAt ( 2 ) - > nextArgument ( ) ; // Find second parameter (format string)
2013-08-06 19:24:35 +02:00
if ( Token : : Match ( formatStringTok , " %str% [,)] " ) ) {
2012-10-30 15:52:45 +01:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find third parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
} else {
continue ;
}
2013-05-14 11:06:16 +02:00
} else if ( Token : : Match ( tok , " snprintf|fnprintf ( " ) | | ( Token : : simpleMatch ( tok , " swprintf ( " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) - > nextArgument ( ) , " %str% " ) ) ) {
2012-10-30 15:52:45 +01:00
const Token * formatStringTok = tok - > tokAt ( 2 ) ;
for ( int i = 0 ; i < 2 & & formatStringTok ; i + + ) {
formatStringTok = formatStringTok - > nextArgument ( ) ; // Find third parameter (format string)
}
2013-08-06 19:24:35 +02:00
if ( Token : : Match ( formatStringTok , " %str% [,)] " ) ) {
2012-10-30 15:52:45 +01:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find fourth parameter (first argument of va_args)
formatString = formatStringTok - > str ( ) ;
} else {
continue ;
}
2012-05-20 11:57:07 +02:00
} else {
continue ;
}
2012-10-30 15:52:45 +01:00
// Count format string parameters..
2012-11-06 19:54:52 +01:00
bool scan = Token : : Match ( tok , " sscanf|fscanf|scanf|swscanf|fwscanf|wscanf " ) ;
2012-10-30 15:52:45 +01:00
unsigned int numFormat = 0 ;
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 ;
}
if ( i = = formatString . end ( ) )
break ;
} else if ( percent ) {
percent = false ;
bool _continue = false ;
std : : string width ;
2013-07-28 16:13:16 +02:00
unsigned int parameterPosition = 0 ;
bool hasParameterPosition = false ;
2012-10-30 15:52:45 +01:00
while ( i ! = formatString . end ( ) & & * i ! = ' ] ' & & ! std : : isalpha ( * i ) ) {
if ( * i = = ' * ' ) {
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 ;
}
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 " ) ) {
invalidScanfArgTypeError_s ( tok , numFormat , specifier , & argInfo ) ;
}
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 ( ) ) {
if ( ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else {
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 ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
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 ( ) ) {
if ( argInfo . typeToken - > isUnsigned ( ) | | ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else {
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 ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
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 ' :
if ( argInfo . typeToken - > originalName ( ) ! = " size_t " )
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 ( ) ) {
if ( ! argInfo . typeToken - > isUnsigned ( ) | | ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else {
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 ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
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 ( ) ) {
if ( ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
else {
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 ' :
if ( i + 1 ! = formatString . end ( ) & & * ( i + 1 ) = = ' 6 ' & &
i + 2 ! = formatString . end ( ) & & * ( i + 2 ) = = ' 4 ' ) {
specifier + = * i + + ;
specifier + = * i + + ;
if ( ( i + 1 ) ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
} else {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
}
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-09-08 20:21:00 +02:00
argInfo . isKnownType ( ) & & ! argInfo . isArrayOrPointer ( ) )
2013-07-21 08:35:01 +02:00
invalidPrintfArgTypeError_s ( tok , numFormat ) ;
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-09-24 06:43:03 +02:00
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|short|long|int|char " ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else {
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 ) ;
} else if ( ! ( argInfo . typeToken - > originalName ( ) ! = " size_t " | |
argInfo . typeToken - > originalName ( ) ! = " ptrdiff_t " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
}
2013-08-10 12:33:55 +02:00
}
2013-09-24 06:43:03 +02:00
} else if ( argInfo . isArrayOrPointer ( ) ) {
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-09-24 06:43:03 +02:00
} else if ( ( argInfo . typeToken - > isUnsigned ( ) | | ! Token : : Match ( argInfo . typeToken , " bool|short|long|int " ) ) & & ! Token : : Match ( argInfo . typeToken , " char|short " ) )
2013-09-05 06:04:41 +02:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else {
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-09-24 06:43:03 +02:00
} else if ( argInfo . isArrayOrPointer ( ) ) {
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-09-24 06:43:03 +02:00
} else if ( ( ! argInfo . typeToken - > isUnsigned ( ) | | ! Token : : Match ( argInfo . typeToken , " char|short|long|int " ) ) & & argInfo . typeToken - > str ( ) ! = " bool " )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else {
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-09-24 06:43:03 +02:00
} else if ( argInfo . isArrayOrPointer ( ) ) {
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-09-24 06:43:03 +02:00
} else if ( ! Token : : Match ( argInfo . typeToken , " float|double " ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2013-09-24 06:43:03 +02:00
else if ( ( specifier [ 0 ] = = ' L ' & & ( ! argInfo . typeToken - > isLong ( ) | | argInfo . typeToken - > str ( ) ! = " double " ) ) | |
( specifier [ 0 ] ! = ' L ' & & argInfo . typeToken - > isLong ( ) ) )
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . isArrayOrPointer ( ) ) {
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
if ( numFormat ! = numFunction )
wrongPrintfScanfArgumentsError ( tok , tok - > str ( ) , numFormat , numFunction ) ;
}
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-09-22 06:56:31 +02:00
} else if ( tok - > str ( ) = = " & " | | tok - > type ( ) = = Token : : eVariable | | tok - > type ( ) = = Token : : eFunction | | Token : : Match ( tok , " %type% :: " ) ) {
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 ;
2013-08-23 05:35:57 +02:00
const Token * varTok = 0 ;
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 ;
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-09-08 20:21:00 +02:00
bool CheckIO : : ArgumentInfo : : isStdVectorOrString ( )
2013-09-07 07:20:06 +02:00
{
if ( Token : : Match ( variableInfo - > typeStartToken ( ) , " std :: vector|array < " ) ) {
typeToken = variableInfo - > typeStartToken ( ) - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
_template = true ;
return true ;
} else if ( Token : : Match ( variableInfo - > typeStartToken ( ) , " std :: string|wstring " ) ) {
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 )
{
if ( tok & & tok - > variable ( ) ) {
2013-09-08 20:21:00 +02:00
if ( Token : : Match ( tok - > variable ( ) - > typeStartToken ( ) , " 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 ( ) - > typeStartToken ( ) - > tokAt ( 4 ) ;
return true ;
} else if ( Token : : Match ( tok - > variable ( ) - > typeStartToken ( ) , " std :: string|wstring " ) ) {
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
< < " format string has "
< < numFormat
< < " parameters but "
< < ( numFormat > numFunction ? " only " : " " )
< < numFunction
2012-07-13 19:36:58 +02:00
< < " are 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 " ;
} else if ( specifier [ 0 ] = = ' I ' ) {
errmsg < < ( isUnsigned ? " unsigned " : " " ) < < " __int64 " ;
} else if ( specifier [ 0 ] = = ' j ' ) {
if ( isUnsigned )
errmsg < < " uintmax_t " ;
else
errmsg < < " intmax_t " ;
} else if ( specifier [ 0 ] = = ' z ' ) {
errmsg < < " size_t " ;
} 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 ( ) ) ;
}
2012-05-20 11:57:07 +02:00
void CheckIO : : invalidPrintfArgTypeError_s ( const Token * tok , unsigned int numFormat )
{
std : : ostringstream errmsg ;
2012-07-13 19:36:58 +02:00
errmsg < < " %s in format string (no. " < < numFormat < < " ) requires a char* given in the argument list. " ;
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-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-08-31 06:26:39 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires a " ;
if ( specifier . find ( " I64 " ) ! = std : : string : : npos )
errmsg < < " long long " ;
else
errmsg < < ( specifier [ 0 ] = = ' l ' ? " long " : " n " )
< < ( specifier [ 0 ] = = ' l ' & & specifier [ 1 ] = = ' l ' ? " long " : " " ) ;
2013-09-05 01:46:58 +02:00
errmsg < < " integer but the argument type is " ;
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-08-29 05:49:16 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires an unsigned " ;
if ( specifier . find ( " I64 " ) ! = std : : string : : npos )
errmsg < < " long long " ;
else
errmsg < < ( specifier [ 0 ] = = ' l ' ? " long " : " " )
< < ( specifier [ 0 ] = = ' l ' & & specifier [ 1 ] = = ' l ' ? " long " : " " ) ;
2013-09-05 01:46:58 +02:00
errmsg < < " integer but the argument type is " ;
argumentType ( errmsg , argInfo ) ;
errmsg < < " . " ;
2012-07-11 19:46:35 +02:00
reportError ( tok , Severity : : warning , " invalidPrintfArgType_uint " , errmsg . str ( ) ) ;
}
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-08-29 05:49:16 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires a signed " ;
if ( specifier . find ( " I64 " ) ! = std : : string : : npos )
errmsg < < " long long " ;
else
errmsg < < ( specifier [ 0 ] = = ' l ' ? " long " : " " )
< < ( specifier [ 0 ] = = ' l ' & & specifier [ 1 ] = = ' l ' ? " long " : " " ) ;
2013-09-05 01:46:58 +02:00
errmsg < < " integer but the argument type is " ;
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-15 16:38:45 +02:00
errmsg < < " % " < < specifier < < " in format string (no. " < < numFormat < < " ) requires a \' " ;
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-09-05 01:46:58 +02:00
type - > stringify ( os , false , true ) ;
2013-09-08 20:21:00 +02:00
if ( type - > strAt ( 1 ) = = " * " & & ! ( argInfo - > functionInfo & & argInfo - > element ) )
os < < " * " ;
else if ( argInfo - > variableInfo & & ! argInfo - > element & & argInfo - > variableInfo - > isArray ( ) )
2013-09-05 01:46:58 +02:00
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
}