2012-05-20 11:57:07 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 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 "symboldatabase.h"
2015-11-29 10:49:10 +01:00
# include "utils.h"
2012-05-20 11:57:07 +02:00
# 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 ;
}
2016-01-25 20:01:48 +01:00
static const CWE CWE664 ( 664U ) ;
static const CWE CWE685 ( 685U ) ;
static const CWE CWE687 ( 687U ) ;
static const CWE CWE910 ( 910U ) ;
2012-05-20 11:57:07 +02:00
//---------------------------------------------------------------------------
// std::cout << std::cout;
//---------------------------------------------------------------------------
void CheckIO : : checkCoutCerrMisusage ( )
{
2014-09-01 17:01:05 +02:00
if ( _tokenizer - > isC ( ) )
return ;
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 ] ;
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-05-22 20:25:54 +02:00
if ( Token : : Match ( tok , " std :: cout|cerr !!. " ) & & tok - > next ( ) - > astParent ( ) & & tok - > next ( ) - > astParent ( ) - > astOperand1 ( ) = = tok - > next ( ) ) {
const Token * tok2 = tok - > next ( ) ;
while ( tok2 - > astParent ( ) & & tok2 - > astParent ( ) - > str ( ) = = " << " ) {
tok2 = tok2 - > astParent ( ) ;
if ( tok2 - > astOperand2 ( ) & & Token : : Match ( tok2 - > astOperand2 ( ) - > previous ( ) , " std :: cout|cerr " ) )
coutCerrMisusageError ( tok , tok2 - > astOperand2 ( ) - > strAt ( 1 ) ) ;
}
}
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 ;
2014-11-13 21:39:14 +01:00
explicit Filepointer ( OpenMode mode_ = UNKNOWN_OM )
2014-11-20 14:20:09 +01:00
: mode ( mode_ ) , mode_indent ( 0 ) , lastOperation ( NONE ) , op_indent ( 0 ) , append_mode ( UNKNOWN_AM ) {
2012-05-22 15:43:40 +02:00
}
} ;
2015-06-20 22:26:51 +02:00
namespace {
2015-11-30 22:13:49 +01:00
const std : : set < std : : string > whitelist = make_container < std : : set < std : : string > > ( )
< < " clearerr " < < " feof " < < " ferror " < < " fgetpos " < < " ftell " < < " setbuf " < < " setvbuf " < < " ungetc " < < " ungetwc " ;
2015-06-20 22:26:51 +02:00
}
2012-05-22 14:30:22 +02:00
void CheckIO : : checkFileUsage ( )
{
2014-03-12 19:22:44 +01:00
const bool windows = _settings - > isWindowsPlatform ( ) ;
2015-04-07 07:07:08 +02:00
const bool printPortability = _settings - > isEnabled ( " portability " ) ;
const bool printWarnings = _settings - > isEnabled ( " warning " ) ;
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 ;
}
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok , " %var% = " ) & &
2014-03-12 19:22:44 +01:00
( 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 ;
}
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok , " %name% ( " ) & & tok - > previous ( ) & & ( ! tok - > previous ( ) - > isName ( ) | | Token : : Match ( tok - > previous ( ) , " return|throw " ) ) ) {
2012-10-30 15:52:45 +01:00
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 ( ) ;
2015-08-14 20:46:13 +02:00
if ( modeTok & & modeTok - > tokType ( ) = = Token : : eString )
2012-10-30 15:52:45 +01:00
mode = modeTok - > strValue ( ) ;
} else
mode = " wb+ " ;
fileTok = tok - > tokAt ( - 2 ) ;
operation = Filepointer : : OPEN ;
2015-01-31 10:50:39 +01:00
} else if ( windows & & Token : : Match ( tok , " fopen_s|freopen_s|_wfopen_s|_wfreopen_s ( & %name% " ) ) {
2014-03-12 19:22:44 +01:00
const Token * modeTok = tok - > tokAt ( 2 ) - > nextArgument ( ) - > nextArgument ( ) ;
2015-08-14 20:46:13 +02:00
if ( modeTok & & modeTok - > tokType ( ) = = Token : : eString )
2014-03-12 19:22:44 +01:00
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 " ) ) {
2015-04-07 07:07:08 +02:00
if ( printPortability & & tok - > str ( ) = = " fflush " ) {
2012-10-30 15:52:45 +01:00
fileTok = tok - > tokAt ( 2 ) ;
2014-09-01 09:00:05 +02:00
if ( fileTok ) {
if ( fileTok - > str ( ) = = " stdin " )
2014-08-31 21:03:33 +02:00
fflushOnInputStreamError ( tok , fileTok - > str ( ) ) ;
2014-09-01 09:00:05 +02:00
else {
Filepointer & f = filepointers [ fileTok - > varId ( ) ] ;
if ( f . mode = = READ_MODE )
fflushOnInputStreamError ( tok , fileTok - > str ( ) ) ;
}
2014-08-31 21:03:33 +02:00
}
2012-10-30 15:52:45 +01:00
}
2014-08-31 21:03:33 +02:00
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 ;
2014-09-11 17:01:08 +02:00
} else if ( ! Token : : Match ( tok , " if|for|while|catch|switch " ) & & _settings - > library . functionpure . find ( tok - > str ( ) ) = = _settings - > library . functionpure . end ( ) ) {
2012-10-30 15:52:45 +01:00
const Token * const end2 = tok - > linkAt ( 1 ) ;
2015-01-27 21:52:52 +01:00
if ( scope - > functionOf & & scope - > functionOf - > isClassOrStruct ( ) & & ! scope - > function - > isStatic ( ) & & ( ( tok - > strAt ( - 1 ) ! = " :: " & & tok - > strAt ( - 1 ) ! = " . " ) | | tok - > strAt ( - 2 ) = = " this " ) ) {
if ( ! tok - > function ( ) | | ( tok - > function ( ) - > nestedIn & & tok - > function ( ) - > nestedIn - > isClassOrStruct ( ) ) ) {
for ( std : : map < unsigned int , Filepointer > : : iterator i = filepointers . begin ( ) ; i ! = filepointers . end ( ) ; + + i ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( i - > first ) ;
if ( ! var | | ! ( var - > isLocal ( ) | | var - > isGlobal ( ) | | var - > isStatic ( ) ) ) {
i - > second . mode = UNKNOWN_OM ;
i - > second . mode_indent = 0 ;
i - > second . op_indent = indent ;
i - > second . lastOperation = Filepointer : : UNKNOWN_OP ;
}
}
continue ;
}
}
2012-10-30 15:52:45 +01:00
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
}
}
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( fileTok , " %name% . " ) )
2013-03-15 06:42:46 +01:00
fileTok = fileTok - > tokAt ( 2 ) ;
2015-07-20 22:40:19 +02:00
if ( ! fileTok | | ! fileTok - > varId ( ) | | fileTok - > strAt ( 1 ) = = " [ " )
2012-10-30 15:52:45 +01:00
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 ;
2015-10-13 15:31:58 +02:00
} else
f . append_mode = Filepointer : : UNKNOWN_AM ;
2012-10-30 15:52:45 +01:00
f . mode_indent = indent ;
break ;
case Filepointer : : POSITIONING :
if ( f . mode = = CLOSED )
useClosedFileError ( tok ) ;
2015-04-07 07:07:08 +02:00
else if ( f . append_mode = = Filepointer : : APPEND & & tok - > str ( ) ! = " fflush " & & printWarnings )
2014-03-17 11:02:03 +01:00
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 )
{
2014-08-31 20:56:05 +02:00
reportError ( tok , Severity : : portability ,
" fflushOnInputStream " , " fflush() called on input stream ' " + varname + " ' may result in undefined behaviour on non-linux systems. " ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : ioWithoutPositioningError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2016-01-25 20:01:48 +01: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. " , CWE664 , false ) ;
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 ,
2016-01-25 20:01:48 +01:00
" readWriteOnlyFile " , " Read operation on a file that was opened only for writing. " , CWE664 , false ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : writeReadOnlyFileError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2016-01-25 20:01:48 +01:00
" writeReadOnlyFile " , " Write operation on a file that was opened only for reading. " , CWE664 , false ) ;
2012-05-22 14:30:22 +02:00
}
void CheckIO : : useClosedFileError ( const Token * tok )
{
reportError ( tok , Severity : : error ,
2016-01-25 20:01:48 +01:00
" useClosedFile " , " Used file that is not opened. " , CWE910 , false ) ;
2012-05-22 14:30:22 +02:00
}
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 ( )
{
2015-08-14 08:03:46 +02:00
if ( ! _settings - > isEnabled ( " warning " ) )
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 ( ) ) {
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 ( ) ;
2015-08-14 20:46:13 +02:00
if ( nextArg & & nextArg - > tokType ( ) = = Token : : eString )
2012-10-30 15:52:45 +01:00
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 ( ) ) ;
2014-07-07 21:25:30 +02:00
for ( std : : size_t i = 1 ; i < formatstr . length ( ) ; i + + ) {
2012-10-30 15:52:45 +01:00
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
2014-03-18 21:41:47 +01:00
else if ( std : : isalpha ( ( unsigned char ) formatstr [ i ] ) | | formatstr [ i ] = = ' [ ' ) {
2015-08-14 08:03:46 +02:00
if ( formatstr [ i ] = = ' s ' | | formatstr [ i ] = = ' [ ' | | formatstr [ i ] = = ' S ' | | ( formatstr [ i ] = = ' l ' & & formatstr [ i + 1 ] = = ' s ' ) ) // #3490 - field width limits are only necessary for string input
invalidScanfError ( tok ) ;
2012-10-30 15:52:45 +01:00
format = false ;
}
2012-05-20 11:57:07 +02:00
}
}
}
}
2015-08-14 08:03:46 +02:00
void CheckIO : : invalidScanfError ( const Token * tok )
2012-05-20 11:57:07 +02:00
{
2015-08-14 08:03:46 +02:00
2015-08-14 12:50:45 +02:00
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 "
" Typing in 5 or more characters may make the program crash. The correct usage "
" here is 'scanf( \" %4s \" , c);', as the maximum field width does not include the "
" terminating null byte. \n "
" Source: http://linux.die.net/man/3/scanf \n "
" Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c "
) ;
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% [,)] " ) & &
2015-01-31 10:50:39 +01:00
argTok - > variable ( ) & &
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 ) ) ) {
2013-10-04 17:30:55 +02:00
* formatArgTok = argTok - > nextArgument ( ) ;
2015-11-06 09:52:22 +01:00
if ( argTok - > values . size ( ) > = 1 & & argTok - > values . front ( ) . tokvalue & & argTok - > values . front ( ) . tokvalue - > tokType ( ) = = Token : : eString )
* formatStringTok = argTok - > values . front ( ) . tokvalue ;
2013-10-04 17:30:55 +02:00
return true ;
}
return false ;
}
2014-05-27 19:15:15 +02:00
// Utility function returning whether iToTest equals iTypename or iOptionalPrefix+iTypename
2015-01-05 01:20:33 +01:00
static inline bool typesMatch ( const std : : string & iToTest , const std : : string & iTypename , const std : : string & iOptionalPrefix = " std:: " )
2014-05-27 19:15:15 +02:00
{
return ( iToTest = = iTypename ) | | ( iToTest = = iOptionalPrefix + iTypename ) ;
}
2012-05-20 11:57:07 +02:00
void CheckIO : : checkWrongPrintfScanfArguments ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2015-04-10 14:18:52 +02:00
const bool isWindows = _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
2014-01-12 12:44:24 +01:00
bool scan = false ;
bool scanf_s = false ;
int formatStringArgNo = - 1 ;
2015-12-24 14:40:48 +01:00
if ( tok - > strAt ( 1 ) = = " ( " & & _settings - > library . formatstr_function ( tok - > str ( ) ) ) {
2014-01-12 12:44:24 +01:00
const std : : map < int , Library : : ArgumentChecks > & argumentChecks = _settings - > library . argumentChecks . at ( tok - > str ( ) ) ;
2015-04-12 14:51:57 +02:00
for ( std : : map < int , Library : : ArgumentChecks > : : const_iterator i = argumentChecks . cbegin ( ) ; i ! = argumentChecks . cend ( ) ; + + 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.
2014-09-02 11:44:51 +02:00
if ( ! findFormat ( static_cast < unsigned int > ( formatStringArgNo ) , tok - > tokAt ( 2 ) , & formatStringTok , & argListTok ) )
2014-01-12 12:44:24 +01:00
continue ;
2015-04-10 14:18:52 +02:00
} else if ( isWindows & & Token : : Match ( tok , " Format|AppendFormat ( " ) & &
2014-01-12 12:44:24 +01:00
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 ;
2015-04-10 14:18:52 +02:00
} else if ( isWindows & & Token : : Match ( tok , " sprintf_s|swprintf_s ( " ) ) {
2013-10-04 17:30:55 +02:00
// 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
}
2015-04-10 14:18:52 +02:00
} else if ( isWindows & & 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 ;
}
2015-08-07 16:16:41 +02:00
if ( ! formatStringTok )
2013-10-05 07:47:52 +02:00
continue ;
2013-10-04 17:30:55 +02:00
2015-10-10 20:08:15 +02:00
checkFormatString ( tok , formatStringTok , argListTok , scan , scanf_s ) ;
}
}
}
void CheckIO : : checkFormatString ( const Token * const tok ,
const Token * const formatStringTok ,
const Token * argListTok ,
const bool scan ,
const bool scanf_s )
{
const bool printWarning = _settings - > isEnabled ( " warning " ) ;
const std : : string & formatString = formatStringTok - > str ( ) ;
// Count format string parameters..
unsigned int numFormat = 0 ;
unsigned int numSecure = 0 ;
bool percent = false ;
const Token * argListTok2 = argListTok ;
std : : set < unsigned int > parameterPositionsUsed ;
for ( std : : string : : const_iterator i = formatString . begin ( ) ; i ! = formatString . end ( ) ; + + i ) {
if ( * i = = ' % ' ) {
percent = ! percent ;
} else if ( percent & & * i = = ' [ ' ) {
while ( i ! = formatString . end ( ) ) {
if ( * i = = ' ] ' ) {
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
percent = false ;
break ;
}
+ + i ;
}
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
if ( i = = formatString . end ( ) )
break ;
} else if ( percent ) {
percent = false ;
bool _continue = false ;
bool skip = false ;
std : : string width ;
unsigned int parameterPosition = 0 ;
bool hasParameterPosition = false ;
while ( i ! = formatString . end ( ) & & * i ! = ' [ ' & & ! std : : isalpha ( ( unsigned char ) * i ) ) {
if ( * i = = ' * ' ) {
skip = true ;
if ( scan )
_continue = true ;
else {
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
}
} else if ( std : : isdigit ( * i ) ) {
width + = * i ;
} else if ( * i = = ' $ ' ) {
parameterPosition = static_cast < unsigned int > ( std : : atoi ( width . c_str ( ) ) ) ;
hasParameterPosition = true ;
width . clear ( ) ;
}
+ + i ;
}
if ( i ! = formatString . end ( ) & & * i = = ' [ ' ) {
while ( i ! = formatString . end ( ) ) {
if ( * i = = ' ] ' ) {
if ( ! skip ) {
2012-05-20 11:57:07 +02:00
numFormat + + ;
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ;
2013-10-01 05:49:44 +02:00
}
2012-10-30 15:52:45 +01:00
break ;
}
2015-10-10 20:08:15 +02:00
+ + i ;
}
if ( scanf_s & & ! skip ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
2013-10-01 05:49:44 +02:00
}
2015-10-10 20:08:15 +02:00
}
_continue = true ;
}
if ( i = = formatString . end ( ) )
break ;
if ( _continue )
continue ;
2013-07-28 16:13:16 +02:00
2015-10-10 20:08:15 +02:00
if ( scan | | * i ! = ' m ' ) { // %m is a non-standard extension that requires no parameter on print functions.
+ + numFormat ;
2012-05-20 11:57:07 +02:00
2015-10-10 20:08:15 +02:00
// Handle parameter positions (POSIX extension) - Ticket #4900
if ( hasParameterPosition ) {
if ( parameterPositionsUsed . find ( parameterPosition ) = = parameterPositionsUsed . end ( ) )
parameterPositionsUsed . insert ( parameterPosition ) ;
else // Parameter already referenced, hence don't consider it a new format
- - numFormat ;
}
2012-10-30 15:52:45 +01:00
2015-10-10 20:08:15 +02:00
// Perform type checks
ArgumentInfo argInfo ( argListTok , _settings , _tokenizer - > isCPP ( ) ) ;
if ( argInfo . typeToken & & ! argInfo . isLibraryType ( _settings ) ) {
if ( scan ) {
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 & & argListTok - > tokType ( ) ! = Token : : eString & &
argInfo . isKnownType ( ) & & argInfo . isArrayOrPointer ( ) & &
( ! Token : : Match ( argInfo . typeToken , " char|wchar_t " ) | |
argInfo . typeToken - > strAt ( - 1 ) = = " const " ) ) {
if ( ! ( argInfo . isArrayOrPointer ( ) & & argInfo . element & & ! argInfo . typeToken - > isStandardType ( ) ) )
invalidScanfArgTypeError_s ( tok , numFormat , specifier , & argInfo ) ;
}
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
done = true ;
break ;
case ' c ' :
if ( scanf_s ) {
numSecure + + ;
if ( argListTok ) {
argListTok = argListTok - > nextArgument ( ) ;
}
}
done = true ;
break ;
case ' x ' :
case ' X ' :
case ' o ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
} else 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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " intmax_t " , " u " ) )
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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " intmax_t " , " u " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' I ' :
if ( specifier . find ( " I64 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
2013-10-27 10:48:49 +01:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
} 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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) & &
! typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) )
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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' t ' :
if ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
break ;
default :
2016-01-15 09:29:29 +01:00
if ( argInfo . typeToken - > str ( ) ! = " int " | | ! argInfo . typeToken - > isUnsigned ( ) )
2015-10-10 20:08:15 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " intmax_t " , " u " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
2013-09-22 06:56:31 +02:00
}
2015-10-10 20:08:15 +02:00
}
}
done = true ;
break ;
case ' n ' :
case ' d ' :
case ' i ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
2015-10-10 20:08:15 +02:00
} else 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 " )
2013-10-27 10:48:49 +01:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
2015-10-10 20:08:15 +02:00
} else if ( argInfo . typeToken - > str ( ) ! = " short " )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
2015-10-10 20:08:15 +02:00
break ;
case ' l ' :
if ( specifier [ 1 ] = = ' l ' ) {
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
else if ( typesMatch ( 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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' I ' :
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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) )
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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) & &
! typesMatch ( argInfo . typeToken - > originalName ( ) , " ssize_t " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
case ' t ' :
if ( ! typesMatch ( 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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , false ) ;
break ;
2013-09-22 06:56:31 +02:00
}
2015-10-10 20:08:15 +02:00
}
}
done = true ;
break ;
case ' u ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " char|short|int|long " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) | | ! argInfo . element )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
} else 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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
2013-10-27 10:48:49 +01:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
} else if ( argInfo . typeToken - > str ( ) ! = " long " | | argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' I ' :
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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) )
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 ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
case ' t ' :
if ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
2015-10-10 20:08:15 +02:00
break ;
case ' L ' :
if ( argInfo . typeToken - > str ( ) ! = " long " | | ! argInfo . typeToken - > isLong ( ) )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
default :
if ( argInfo . typeToken - > str ( ) ! = " int " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
else if ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
typesMatch ( argInfo . typeToken - > originalName ( ) , " ssize_t " ) | |
argInfo . typeToken - > originalName ( ) = = " uintmax_t " )
invalidScanfArgTypeError_int ( tok , numFormat , specifier , & argInfo , true ) ;
break ;
2013-09-22 06:56:31 +02:00
}
2015-10-10 20:08:15 +02:00
}
}
done = true ;
break ;
case ' e ' :
case ' E ' :
case ' f ' :
case ' g ' :
case ' G ' :
case ' a ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " float|double " ) ) {
if ( argInfo . typeToken - > isStandardType ( ) )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else 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 ( ) )
2013-10-27 10:48:49 +01:00
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( argInfo . typeToken - > str ( ) ! = " double " | | argInfo . typeToken - > isLong ( ) )
2013-09-22 06:56:31 +02:00
invalidScanfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
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 ;
2013-09-22 06:56:31 +02:00
}
2012-10-30 15:52:45 +01:00
}
2012-06-23 07:52:52 +02:00
}
2015-10-10 20:08:15 +02:00
done = true ;
break ;
case ' I ' :
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 ' ) ) {
specifier + = * i + + ;
specifier + = * i + + ;
if ( ( i + 1 ) ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
2013-07-21 08:35:01 +02:00
done = true ;
2015-10-10 20:08:15 +02:00
} else {
specifier + = * i + + ;
}
} else {
if ( ( i + 1 ) ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
2013-08-10 12:33:55 +02:00
specifier + = * i ;
2015-10-10 20:08:15 +02:00
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
}
break ;
case ' h ' :
case ' l ' :
if ( i + 1 ! = formatString . end ( ) & & * ( i + 1 ) = = * i )
specifier + = * i + + ;
2015-12-17 15:40:54 +01:00
// fallthrough
2015-10-10 20:08:15 +02:00
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 ;
}
}
} else if ( ! scan & & printWarning ) {
std : : string specifier ;
bool done = false ;
while ( ! done ) {
switch ( * i ) {
case ' s ' :
if ( argListTok - > tokType ( ) ! = Token : : eString & &
argInfo . isKnownType ( ) & & ! argInfo . isArrayOrPointer ( ) ) {
if ( ! Token : : Match ( argInfo . typeToken , " char|wchar_t " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_s ( tok , numFormat , & argInfo ) ;
}
}
done = true ;
break ;
case ' n ' :
if ( ( argInfo . isKnownType ( ) & & ( ! argInfo . isArrayOrPointer ( ) | | argInfo . typeToken - > strAt ( - 1 ) = = " const " ) ) | | argListTok - > tokType ( ) = = Token : : eString )
invalidPrintfArgTypeError_n ( tok , numFormat , & argInfo ) ;
done = true ;
break ;
case ' c ' :
case ' x ' :
case ' X ' :
case ' o ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|short|long|int|char|wchar_t " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +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 " ) )
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
break ;
case ' z ' :
if ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' t ' :
if ( ! typesMatch ( 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 ( ) )
2013-10-27 10:48:49 +01:00
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
typesMatch ( 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 " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|wchar_t|int " ) )
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
break ;
2013-07-21 08:35:01 +02:00
}
2015-10-10 20:08:15 +02:00
}
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_int ( tok , numFormat , specifier , & argInfo ) ;
}
done = true ;
break ;
case ' d ' :
case ' i ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString ) {
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . typeToken - > isUnsigned ( ) & & ! Token : : Match ( argInfo . typeToken , " char|short " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int|long " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
} 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 ( typesMatch ( 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 ( ) )
2013-09-08 20:21:00 +02:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
else if ( typesMatch ( 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 ( ! typesMatch ( 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 ( ) )
2013-10-27 10:48:49 +01:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
2013-10-27 10:48:49 +01:00
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
case ' z ' :
if ( ! typesMatch ( argInfo . typeToken - > originalName ( ) , " ssize_t " ) )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
default :
if ( ! Token : : Match ( argInfo . typeToken , " bool|char|short|int " ) )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
else if ( typesMatch ( argInfo . typeToken - > originalName ( ) , " ptrdiff_t " ) | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
break ;
2013-07-21 08:35:01 +02:00
}
2015-10-10 20:08:15 +02:00
}
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_sint ( tok , numFormat , specifier , & argInfo ) ;
}
done = true ;
break ;
case ' u ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString ) {
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
} 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 ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +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 ( typesMatch ( 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 ( typesMatch ( 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 " )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
break ;
case ' z ' :
if ( ! typesMatch ( 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 ( ) )
2013-10-27 10:48:49 +01:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( specifier . find ( " I32 " ) ! = std : : string : : npos ) {
if ( argInfo . typeToken - > str ( ) ! = " int " | | argInfo . typeToken - > isLong ( ) )
2013-10-27 10:48:49 +01:00
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +02:00
} else if ( ! typesMatch ( 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 ( typesMatch ( argInfo . typeToken - > originalName ( ) , " size_t " ) | |
argInfo . typeToken - > originalName ( ) = = " intmax_t " )
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
break ;
2012-10-30 15:52:45 +01:00
}
2015-10-10 20:08:15 +02:00
}
} else if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
invalidPrintfArgTypeError_uint ( tok , numFormat , specifier , & argInfo ) ;
}
done = true ;
break ;
case ' p ' :
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidPrintfArgTypeError_p ( tok , numFormat , & argInfo ) ;
else if ( argInfo . isKnownType ( ) & & ! argInfo . isArrayOrPointer ( ) )
invalidPrintfArgTypeError_p ( tok , numFormat , & argInfo ) ;
done = true ;
break ;
case ' e ' :
case ' E ' :
case ' f ' :
case ' g ' :
case ' G ' :
specifier + = * i ;
if ( argInfo . typeToken - > tokType ( ) = = Token : : eString )
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
else if ( argInfo . isKnownType ( ) ) {
if ( argInfo . isArrayOrPointer ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
} else if ( ! Token : : Match ( argInfo . typeToken , " float|double " ) ) {
if ( ! ( ! argInfo . isArrayOrPointer ( ) & & argInfo . element ) )
2013-09-05 01:46:58 +02:00
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
2015-10-10 20:08:15 +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 ( ) & & ! argInfo . element ) {
// use %p on pointers and arrays
invalidPrintfArgTypeError_float ( tok , numFormat , specifier , & argInfo ) ;
}
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 ) {
if ( i + 1 ! = formatString . end ( ) ) {
if ( ! isalpha ( * ( i + 2 ) ) ) {
std : : string modifier ;
modifier + = * i ;
modifier + = * ( i + 1 ) ;
invalidLengthModifierError ( tok , numFormat , modifier ) ;
done = true ;
2013-07-21 08:35:01 +02:00
} else {
2015-10-10 20:08:15 +02:00
specifier = * i + + ;
2013-08-10 12:37:31 +02:00
specifier + = * i + + ;
2013-07-21 08:35:01 +02:00
}
2015-10-10 20:08:15 +02:00
} else {
done = true ;
}
} else {
if ( i ! = formatString . end ( ) ) {
if ( ! isalpha ( * ( i + 1 ) ) ) {
std : : string modifier ;
modifier + = * i ;
invalidLengthModifierError ( tok , numFormat , modifier ) ;
2013-07-22 08:28:29 +02:00
done = true ;
} else {
2015-10-10 20:08:15 +02:00
specifier = * i + + ;
2012-10-30 15:52:45 +01:00
}
2015-10-10 20:08:15 +02:00
} else {
2013-07-21 08:35:01 +02:00
done = true ;
2012-10-21 08:50:29 +02:00
}
}
2015-10-10 20:08:15 +02:00
break ;
case ' I ' : // Microsoft extension: I for size_t and ptrdiff_t, I32 for __int32, and I64 for __int64
if ( ( * ( i + 1 ) = = ' 3 ' & & * ( i + 2 ) = = ' 2 ' ) | |
( * ( i + 1 ) = = ' 6 ' & & * ( i + 2 ) = = ' 4 ' ) ) {
specifier + = * i + + ;
specifier + = * i + + ;
}
2015-12-17 15:40:54 +01:00
// fallthrough
2015-10-10 20:08:15 +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
if ( i ! = formatString . end ( ) & & ! isalpha ( * ( i + 1 ) ) ) {
specifier + = * i ;
invalidLengthModifierError ( tok , numFormat , specifier ) ;
done = true ;
} else {
specifier + = * i + + ;
}
break ;
default :
done = true ;
break ;
2012-05-20 11:57:07 +02:00
}
}
2012-10-30 15:52:45 +01:00
}
2012-05-20 11:57:07 +02:00
}
2015-10-10 20:08:15 +02:00
if ( argListTok )
argListTok = argListTok - > nextArgument ( ) ; // Find next argument
2012-10-30 15:52:45 +01:00
}
2015-10-10 20:08:15 +02:00
}
}
2013-07-28 16:13:16 +02:00
2015-10-10 20:08:15 +02:00
// Count printf/scanf parameters..
unsigned int numFunction = 0 ;
while ( argListTok2 ) {
numFunction + + ;
argListTok2 = argListTok2 - > nextArgument ( ) ; // Find next argument
}
2012-05-20 11:57:07 +02:00
2015-10-10 20:08:15 +02:00
if ( printWarning ) {
// Check that all parameter positions reference an actual parameter
for ( std : : set < unsigned int > : : const_iterator it = parameterPositionsUsed . begin ( ) ; it ! = parameterPositionsUsed . end ( ) ; + + it ) {
if ( ( * it = = 0 ) | | ( * it > numFormat ) )
wrongPrintfScanfPosixParameterPositionError ( tok , tok - > str ( ) , * it , numFormat ) ;
2012-10-30 15:52:45 +01:00
}
2012-05-20 11:57:07 +02:00
}
2015-10-10 20:08:15 +02:00
// Mismatching number of parameters => warning
if ( ( numFormat + numSecure ) ! = numFunction )
wrongPrintfScanfArgumentsError ( tok , tok - > originalName ( ) . empty ( ) ? tok - > str ( ) : tok - > originalName ( ) , numFormat + numSecure , 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
2015-06-17 21:25:15 +02:00
CheckIO : : ArgumentInfo : : ArgumentInfo ( const Token * tok , const Settings * settings , bool _isCPP )
: variableInfo ( nullptr )
, typeToken ( nullptr )
, functionInfo ( nullptr )
2015-08-15 19:46:31 +02:00
, tempToken ( nullptr )
2013-09-03 05:50:19 +02:00
, element ( false )
2013-09-08 20:21:00 +02:00
, _template ( false )
2013-09-22 06:56:31 +02:00
, address ( false )
2015-06-17 21:25:15 +02:00
, isCPP ( _isCPP )
2013-08-20 06:16:31 +02:00
{
2015-10-05 19:04:29 +02:00
if ( ! tok )
return ;
2015-10-05 10:12:30 +02:00
// Use AST type info
// TODO: This is a bailout so that old code is used in simple cases. Remove the old code and always use the AST type.
2015-10-11 17:35:54 +02:00
if ( ! Token : : Match ( tok , " %str%|%name% ,|) " ) ) {
2015-10-05 10:12:30 +02:00
const ValueType * valuetype = tok - > argumentType ( ) ;
2015-10-05 19:59:15 +02:00
if ( valuetype & & valuetype - > type > = ValueType : : Type : : BOOL ) {
2015-10-07 19:08:26 +02:00
typeToken = tempToken = new Token ( 0 ) ;
if ( valuetype - > constness & 1 ) {
tempToken - > str ( " const " ) ;
tempToken - > insertToken ( " a " ) ;
tempToken = tempToken - > next ( ) ;
}
2015-10-05 19:59:15 +02:00
if ( valuetype - > pointer = = 0U & & valuetype - > type < = ValueType : : INT )
tempToken - > str ( " int " ) ;
else if ( valuetype - > type = = ValueType : : BOOL )
tempToken - > str ( " bool " ) ;
else if ( valuetype - > type = = ValueType : : CHAR )
tempToken - > str ( " char " ) ;
else if ( valuetype - > type = = ValueType : : SHORT )
tempToken - > str ( " short " ) ;
else if ( valuetype - > type = = ValueType : : INT )
2015-10-05 10:12:30 +02:00
tempToken - > str ( " int " ) ;
else if ( valuetype - > type = = ValueType : : LONG )
tempToken - > str ( " long " ) ;
2015-10-05 19:20:42 +02:00
else if ( valuetype - > type = = ValueType : : LONGLONG ) {
2015-10-05 10:12:30 +02:00
tempToken - > str ( " long " ) ;
2015-10-05 19:20:42 +02:00
tempToken - > isLong ( true ) ;
} else if ( valuetype - > type = = ValueType : : FLOAT )
2015-10-05 10:12:30 +02:00
tempToken - > str ( " float " ) ;
else if ( valuetype - > type = = ValueType : : DOUBLE )
tempToken - > str ( " double " ) ;
2015-10-08 19:52:24 +02:00
else if ( valuetype - > type = = ValueType : : LONGDOUBLE ) {
tempToken - > str ( " double " ) ;
tempToken - > isLong ( true ) ;
}
2015-10-05 10:12:30 +02:00
if ( valuetype - > isIntegral ( ) ) {
if ( valuetype - > sign = = ValueType : : Sign : : UNSIGNED )
tempToken - > isUnsigned ( true ) ;
else if ( valuetype - > sign = = ValueType : : Sign : : SIGNED )
tempToken - > isSigned ( true ) ;
}
2015-10-07 20:24:17 +02:00
if ( ! valuetype - > originalTypeName . empty ( ) )
tempToken - > originalName ( valuetype - > originalTypeName ) ;
2015-10-05 19:59:15 +02:00
for ( unsigned int p = 0 ; p < valuetype - > pointer ; p + + )
tempToken - > insertToken ( " * " ) ;
2015-10-07 19:08:26 +02:00
tempToken = const_cast < Token * > ( typeToken ) ;
2015-10-05 10:12:30 +02:00
return ;
}
}
2015-10-05 19:04:29 +02:00
if ( tok - > tokType ( ) = = Token : : eString ) {
typeToken = tok ;
return ;
} else if ( tok - > str ( ) = = " & " | | tok - > tokType ( ) = = Token : : eVariable | |
tok - > tokType ( ) = = Token : : eFunction | | Token : : Match ( tok , " %type% :: " ) | |
( Token : : Match ( tok , " static_cast|reinterpret_cast|const_cast < " ) & &
Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > ( " ) & &
Token : : Match ( tok - > linkAt ( 1 ) - > linkAt ( 1 ) , " ) ,|) " ) ) ) {
if ( Token : : Match ( tok , " static_cast|reinterpret_cast|const_cast " ) ) {
typeToken = tok - > tokAt ( 2 ) ;
while ( typeToken - > str ( ) = = " const " | | typeToken - > str ( ) = = " extern " )
typeToken = typeToken - > next ( ) ;
2013-09-03 05:50:19 +02:00
return ;
2015-10-05 19:04:29 +02:00
}
if ( tok - > str ( ) = = " & " ) {
address = true ;
tok = tok - > next ( ) ;
}
while ( Token : : Match ( tok , " %type% :: " ) )
tok = tok - > tokAt ( 2 ) ;
if ( ! tok | | ! ( tok - > tokType ( ) = = Token : : eVariable | | tok - > tokType ( ) = = Token : : eFunction ) )
return ;
const Token * varTok = nullptr ;
const Token * tok1 = tok - > next ( ) ;
for ( ; tok1 ; tok1 = tok1 - > next ( ) ) {
if ( tok1 - > str ( ) = = " , " | | tok1 - > str ( ) = = " ) " ) {
if ( tok1 - > previous ( ) - > str ( ) = = " ] " ) {
varTok = tok1 - > linkAt ( - 1 ) - > previous ( ) ;
if ( varTok - > str ( ) = = " ) " & & varTok - > link ( ) - > previous ( ) - > tokType ( ) = = 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 ;
2014-07-28 09:16:35 +02:00
while ( typeToken - > str ( ) = = " const " | | typeToken - > str ( ) = = " extern " )
2013-09-22 06:56:31 +02:00
typeToken = typeToken - > next ( ) ;
2013-09-03 05:50:19 +02:00
functionInfo = function ;
2015-10-05 19:04:29 +02:00
element = true ;
2014-08-18 14:02:35 +02:00
}
return ;
2013-09-03 05:50:19 +02:00
}
2015-10-05 19:04:29 +02:00
} else if ( tok1 - > previous ( ) - > str ( ) = = " ) " & & tok1 - > linkAt ( - 1 ) - > previous ( ) - > tokType ( ) = = Token : : eFunction ) {
const Function * function = tok1 - > linkAt ( - 1 ) - > previous ( ) - > function ( ) ;
if ( function & & function - > retDef ) {
typeToken = function - > retDef ;
while ( typeToken - > str ( ) = = " const " | | typeToken - > str ( ) = = " extern " )
typeToken = typeToken - > next ( ) ;
functionInfo = function ;
element = false ;
}
2013-11-08 12:44:05 +01:00
return ;
2015-10-05 19:04:29 +02:00
} else
2013-11-08 12:44:05 +01:00
varTok = tok1 - > previous ( ) ;
2015-10-05 19:04:29 +02:00
break ;
} else if ( tok1 - > str ( ) = = " ( " | | tok1 - > str ( ) = = " { " || tok1->str() == " [ " )
tok1 = tok1 - > link ( ) ;
else if ( tok1 - > link ( ) & & tok1 - > str ( ) = = " < " )
tok1 = tok1 - > link ( ) ;
// check for some common well known functions
else if ( isCPP & & ( ( Token : : Match ( tok1 - > previous ( ) , " %var% . size|empty|c_str ( ) [,)] " ) & & isStdContainer ( tok1 - > previous ( ) ) ) | |
( Token : : Match ( tok1 - > previous ( ) , " ] . size|empty|c_str ( ) [,)] " ) & & isStdContainer ( tok1 - > previous ( ) - > link ( ) - > previous ( ) ) ) ) ) {
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 ) {
if ( settings - > sizeof_long = = 4 ) {
tempToken - > str ( " long " ) ;
} else {
tempToken - > str ( " int " ) ;
}
2013-11-08 12:44:05 +01:00
}
2015-10-05 19:04:29 +02:00
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 ( " * " ) ;
if ( typeToken - > strAt ( 2 ) = = " string " )
tempToken - > insertToken ( " char " ) ;
else
tempToken - > insertToken ( " wchar_t " ) ;
}
typeToken = tempToken ;
return ;
2013-08-23 05:35:57 +02:00
}
2013-08-20 06:16:31 +02:00
2015-10-05 19:04:29 +02:00
// 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 ( ) ;
2013-09-03 05:50:19 +02:00
variableInfo = varTok - > variable ( ) ;
2013-08-30 05:41:59 +02:00
2015-10-05 19:04:29 +02:00
if ( ! variableInfo | | ! isStdVectorOrString ( ) ) {
variableInfo = 0 ;
typeToken = 0 ;
2013-09-03 05:50:19 +02:00
}
2013-08-30 05:41:59 +02:00
2013-09-03 05:50:19 +02:00
return ;
2015-10-05 19:04:29 +02:00
} else if ( ! ( tok1 - > str ( ) = = " . " | | tok1 - > tokType ( ) = = Token : : eVariable | | tok1 - > tokType ( ) = = Token : : eFunction ) )
return ;
}
if ( varTok ) {
variableInfo = varTok - > variable ( ) ;
element = tok1 - > previous ( ) - > str ( ) = = " ] " ;
// look for std::vector operator [] and use template type as return type
if ( variableInfo ) {
if ( element & & isStdVectorOrString ( ) ) { // isStdVectorOrString sets type token if true
element = false ; // not really an array element
} else
typeToken = variableInfo - > typeStartToken ( ) ;
2013-08-23 05:35:57 +02:00
}
2015-10-05 19:04:29 +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 ;
}
}
2015-06-10 21:14:17 +02:00
namespace {
2015-11-30 22:13:49 +01:00
const std : : set < std : : string > stl_vector = make_container < std : : set < std : : string > > ( ) < < " array " < < " vector " ;
const std : : set < std : : string > stl_string = make_container < std : : set < std : : string > > ( ) < < " string " < < " u16string " < < " u32string " < < " wstring " ;
2015-06-10 21:14:17 +02:00
}
2015-05-17 20:02:41 +02:00
2013-09-08 20:21:00 +02:00
bool CheckIO : : ArgumentInfo : : isStdVectorOrString ( )
2013-09-07 07:20:06 +02:00
{
2015-06-17 09:09:23 +02:00
if ( ! isCPP )
return false ;
2014-01-30 05:26:48 +01:00
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 ( ) ) {
2015-09-15 14:34:12 +02:00
const std : : vector < Type : : BaseInfo > & derivedFrom = variableInfo - > type ( ) - > derivedFrom ;
for ( std : : size_t i = 0 , size = derivedFrom . size ( ) ; i < size ; + + i ) {
const Token * nameTok = derivedFrom [ i ] . nameTok ;
if ( Token : : Match ( nameTok , " std :: vector|array < " ) ) {
typeToken = nameTok - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
_template = true ;
return true ;
2015-09-15 14:34:12 +02:00
} else if ( Token : : Match ( nameTok , " std :: string|wstring " ) ) {
2013-09-08 20:21:00 +02:00
tempToken = new Token ( 0 ) ;
tempToken - > fileIndex ( variableInfo - > typeStartToken ( ) - > fileIndex ( ) ) ;
tempToken - > linenr ( variableInfo - > typeStartToken ( ) - > linenr ( ) ) ;
2015-09-15 14:34:12 +02:00
if ( nameTok - > strAt ( 2 ) = = " string " )
2013-09-08 20:21:00 +02:00
tempToken - > str ( " char " ) ;
else
tempToken - > str ( " wchar_t " ) ;
typeToken = tempToken ;
2013-09-07 07:20:06 +02:00
return true ;
}
}
2014-10-20 06:33:36 +02:00
} else if ( variableInfo - > type ( ) ) {
const Scope * classScope = variableInfo - > type ( ) - > classScope ;
if ( classScope ) {
std : : list < Function > : : const_iterator functions ;
for ( functions = classScope - > functionList . begin ( ) ;
functions ! = classScope - > functionList . end ( ) ; + + functions ) {
if ( functions - > name ( ) = = " operator[] " ) {
if ( Token : : Match ( functions - > retDef , " %type% & " ) ) {
typeToken = functions - > retDef ;
return true ;
}
}
}
}
2013-09-07 07:20:06 +02:00
}
return false ;
}
2015-06-10 21:14:17 +02:00
namespace {
2015-11-30 22:13:49 +01:00
const std : : set < std : : string > stl_container = make_container < std : : set < std : : string > > ( ) < <
2015-05-17 20:02:41 +02:00
" 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 "
;
2015-06-10 21:14:17 +02:00
}
bool CheckIO : : ArgumentInfo : : isStdContainer ( const Token * tok )
{
2015-06-17 09:09:23 +02:00
if ( ! isCPP )
return false ;
2013-09-07 07:20:06 +02:00
if ( tok & & tok - > variable ( ) ) {
2014-07-04 08:56:43 +02:00
const Variable * variable = tok - > variable ( ) ;
if ( variable - > isStlType ( stl_container ) ) {
typeToken = variable - > typeStartToken ( ) - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
return true ;
2014-07-04 08:56:43 +02:00
} else if ( variable - > isStlType ( stl_string ) ) {
typeToken = variable - > typeStartToken ( ) ;
2013-09-07 07:20:06 +02:00
return true ;
2014-07-04 08:56:43 +02:00
} else if ( variable - > type ( ) & & ! variable - > type ( ) - > derivedFrom . empty ( ) ) {
const std : : vector < Type : : BaseInfo > & derivedFrom = variable - > type ( ) - > derivedFrom ;
2015-09-15 14:34:12 +02:00
for ( std : : size_t i = 0 , size = derivedFrom . size ( ) ; i < size ; + + i ) {
2014-07-04 08:56:43 +02:00
const Token * nameTok = derivedFrom [ i ] . nameTok ;
if ( Token : : Match ( 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 = nameTok - > tokAt ( 4 ) ;
2013-09-08 20:21:00 +02:00
return true ;
2014-07-04 08:56:43 +02:00
} else if ( Token : : Match ( nameTok , " std :: string|wstring " ) ) {
typeToken = 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 ) ;
const Token * varTypeTok = typeToken ;
if ( varTypeTok - > str ( ) = = " std " )
varTypeTok = varTypeTok - > tokAt ( 2 ) ;
2014-09-05 12:03:08 +02:00
return ( ( variableInfo - > isStlStringType ( ) | | ( varTypeTok - > strAt ( 1 ) = = " < " & & varTypeTok - > linkAt ( 1 ) & & varTypeTok - > linkAt ( 1 ) - > strAt ( 1 ) ! = " :: " ) ) & & ! variableInfo - > isArrayOrPointer ( ) ) ;
2013-09-03 05:50:19 +02:00
}
bool CheckIO : : ArgumentInfo : : isKnownType ( ) const
{
if ( variableInfo )
return ( typeToken - > isStandardType ( ) | | typeToken - > next ( ) - > isStandardType ( ) | | isComplexType ( ) ) ;
else if ( functionInfo )
2014-07-28 09:16:35 +02:00
return ( typeToken - > isStandardType ( ) | | functionInfo - > retType | | Token : : Match ( typeToken , " std :: string|wstring " ) ) ;
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
}
2014-06-12 07:01:44 +02:00
bool CheckIO : : ArgumentInfo : : isLibraryType ( const Settings * settings ) const
{
return typeToken & & typeToken - > isStandardType ( ) & & settings - > library . podtype ( typeToken - > str ( ) ) ;
}
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 ;
2015-01-06 15:08:25 +01:00
if ( severity ! = Severity : : error & & ! _settings - > isEnabled ( " warning " ) )
2012-05-20 11:57:07 +02:00
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
2016-01-25 20:01:48 +01:00
reportError ( tok , severity , " wrongPrintfScanfArgNum " , errmsg . str ( ) , CWE685 , false ) ;
2012-05-20 11:57:07 +02:00
}
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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 )
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
2013-09-22 06:56:31 +02:00
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 )
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
2013-09-22 06:56:31 +02:00
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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 ;
2015-08-14 20:46:13 +02:00
if ( type - > tokType ( ) = = Token : : eString ) {
2013-08-31 06:26:39 +02:00
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 ) ;
}
2014-09-29 14:50:00 +02:00
type - > stringify ( os , false , true , false ) ;
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 " ;
2014-09-29 14:50:00 +02:00
type - > stringify ( os , false , true , false ) ;
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
{
2015-01-06 15:08:25 +01:00
if ( ! _settings - > isEnabled ( " warning " ) )
return ;
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
{
2014-09-01 09:33:58 +02:00
MathLib : : bigint arrlen = 0 ;
std : : string varname ;
2012-06-23 07:52:52 +02:00
if ( var ) {
2014-09-01 09:33:58 +02:00
arrlen = var - > dimension ( 0 ) ;
varname = var - > name ( ) ;
}
2012-06-23 07:52:52 +02:00
2014-09-01 09:33:58 +02:00
std : : ostringstream errmsg ;
if ( arrlen > width ) {
if ( ! _settings - > inconclusive | | ! _settings - > isEnabled ( " warning " ) )
return ;
errmsg < < " Width " < < width < < " given in format string (no. " < < numFormat < < " ) is smaller than destination buffer "
< < " ' " < < varname < < " [ " < < arrlen < < " ]'. " ;
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : warning , " invalidScanfFormatWidth_smaller " , errmsg . str ( ) , CWE ( 0U ) , true ) ;
2014-09-01 09:33:58 +02:00
} else {
errmsg < < " Width " < < width < < " given in format string (no. " < < numFormat < < " ) is larger than destination buffer ' "
< < varname < < " [ " < < arrlen < < " ]', use % " < < ( arrlen - 1 ) < < " s to prevent overflowing it. " ;
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : error , " invalidScanfFormatWidth " , errmsg . str ( ) , CWE687 , false ) ;
2014-09-01 09:33:58 +02:00
}
2012-06-23 07:52:52 +02:00
}