2009-01-26 20:14:46 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-01-26 20:14:46 +01: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
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-26 20:14:46 +01:00
*/
//---------------------------------------------------------------------------
# include "checkother.h"
2009-05-02 10:45:15 +02:00
# include "mathlib.h"
2009-03-20 18:16:21 +01:00
# include "tokenize.h"
2009-12-14 20:30:31 +01:00
# include "executionpath.h"
2009-03-20 18:16:21 +01:00
2009-02-04 19:49:19 +01:00
# include <algorithm>
2009-01-26 20:14:46 +01:00
# include <list>
# include <map>
# include <sstream>
# include <cstring>
# include <cctype>
2009-12-06 18:41:28 +01:00
# include <memory>
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
2009-03-20 18:16:21 +01:00
// Register this check class (by creating a static instance of it)
namespace
2009-01-26 20:14:46 +01:00
{
2009-03-20 18:16:21 +01:00
CheckOther instance ;
2009-01-26 20:14:46 +01:00
}
2009-03-20 18:16:21 +01:00
//---------------------------------------------------------------------------
2009-01-26 20:14:46 +01:00
2009-07-05 22:16:43 +02:00
void CheckOther : : warningOldStylePointerCast ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Old style pointer casting..
2009-09-24 22:46:08 +02:00
if ( ! Token : : Match ( tok , " ( const| %type% * ) %var% " ) & &
! Token : : Match ( tok , " ( const| %type% * ) (| new " ) )
2009-01-26 20:14:46 +01:00
continue ;
2009-07-20 21:52:27 +02:00
int addToIndex = 0 ;
2009-07-27 11:24:24 +02:00
if ( tok - > tokAt ( 1 ) - > str ( ) = = " const " )
2009-07-20 21:52:27 +02:00
addToIndex = 1 ;
2009-07-27 11:24:24 +02:00
if ( tok - > tokAt ( 4 + addToIndex ) - > str ( ) = = " const " )
2009-06-18 22:26:21 +02:00
continue ;
2009-01-26 20:14:46 +01:00
// Is "type" a class?
2009-07-20 21:52:27 +02:00
const std : : string pattern ( " class " + tok - > tokAt ( 1 + addToIndex ) - > str ( ) ) ;
2009-01-26 20:14:46 +01:00
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
continue ;
2009-03-21 17:58:13 +01:00
cstyleCastError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
}
//---------------------------------------------------------------------------
// Redundant code..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : warningRedundantCode ( )
2009-01-26 20:14:46 +01:00
{
// if (p) delete p
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-07-18 16:42:08 +02:00
if ( ! Token : : simpleMatch ( tok , " if ( " ) )
2009-01-26 20:14:46 +01:00
continue ;
2009-09-28 23:18:40 +02:00
std : : string varname ;
2009-07-18 16:42:08 +02:00
const Token * tok2 = tok - > tokAt ( 2 ) ;
/*
* Possible if - constructions :
*
* if ( var )
* if ( this - > var )
* if ( Foo : : var )
*
* */
2009-09-28 23:18:40 +02:00
while ( Token : : Match ( tok2 , " %var% .|:: " ) )
2009-07-18 20:35:22 +02:00
{
2009-09-28 23:18:40 +02:00
varname . append ( tok2 - > str ( ) ) ;
varname . append ( tok2 - > next ( ) - > str ( ) ) ;
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-26 20:14:46 +01:00
}
2009-07-18 16:42:08 +02:00
2009-09-28 23:18:40 +02:00
if ( ! Token : : Match ( tok2 , " %var% ) { " ) )
2009-01-26 20:14:46 +01:00
continue ;
2009-09-28 23:18:40 +02:00
varname . append ( tok2 - > str ( ) ) ;
tok2 = tok2 - > tokAt ( 3 ) ;
2009-07-18 16:42:08 +02:00
/*
* Possible constructions :
*
* - delete % var %
* - delete [ ] % var %
* - free ( % var )
* - kfree ( % var % )
*
* Where % var % may be :
* - just variable name ( var )
* - class member ( this - > var )
* - static member ( Class : : var )
*
* */
2009-09-28 23:18:40 +02:00
bool funcHasBracket = false ;
2009-07-18 20:35:22 +02:00
if ( Token : : Match ( tok2 , " free|kfree ( " ) )
{
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
funcHasBracket = true ;
2009-07-18 20:35:22 +02:00
}
else if ( tok2 - > str ( ) = = " delete " )
{
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > next ( ) ;
2009-07-18 20:35:22 +02:00
if ( Token : : simpleMatch ( tok2 , " [ ] " ) )
{
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-01-26 20:14:46 +01:00
}
}
2009-07-18 16:42:08 +02:00
2009-09-28 23:18:40 +02:00
std : : string varname2 ;
while ( Token : : Match ( tok2 , " %var% ::|. " ) )
2009-07-18 20:35:22 +02:00
{
2009-09-28 23:18:40 +02:00
varname2 . append ( tok2 - > str ( ) ) ;
varname2 . append ( tok2 - > next ( ) - > str ( ) ) ;
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
}
2009-09-28 23:18:40 +02:00
varname2 . append ( tok2 - > str ( ) ) ;
if ( Token : : Match ( tok2 , " %var% " ) & & varname = = varname2 )
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > next ( ) ;
2009-09-28 23:18:40 +02:00
else
continue ;
2009-07-18 16:42:08 +02:00
2009-07-18 20:35:22 +02:00
if ( funcHasBracket )
{
if ( tok2 - > str ( ) ! = " ) " )
{
2009-09-28 23:18:40 +02:00
continue ;
2009-07-18 20:35:22 +02:00
}
else
{
2009-07-18 16:42:08 +02:00
tok2 = tok2 - > next ( ) ;
2009-01-26 20:14:46 +01:00
}
2009-07-18 16:42:08 +02:00
}
2009-09-28 23:18:40 +02:00
if ( ! Token : : Match ( tok2 , " ; } !!else " ) )
2009-07-18 20:35:22 +02:00
{
2009-09-28 23:18:40 +02:00
continue ;
2009-01-26 20:14:46 +01:00
}
2009-09-28 23:18:40 +02:00
redundantIfDelete0Error ( tok ) ;
2009-01-26 20:14:46 +01:00
}
// Redundant condition
// if (haystack.find(needle) != haystack.end())
// haystack.remove(needle);
redundantCondition2 ( ) ;
}
//---------------------------------------------------------------------------
void CheckOther : : redundantCondition2 ( )
{
const char pattern [ ] = " if ( %var% . find ( %any% ) != %var% . end ( ) ) "
" {|{| "
" %var% . remove ( %any% ) ; "
" }|}| " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ;
while ( tok )
{
2009-07-27 11:24:24 +02:00
bool b ( tok - > tokAt ( 15 ) - > str ( ) = = " { " );
2009-01-26 20:14:46 +01:00
// Get tokens for the fields %var% and %any%
const Token * var1 = tok - > tokAt ( 2 ) ;
const Token * any1 = tok - > tokAt ( 6 ) ;
const Token * var2 = tok - > tokAt ( 9 ) ;
const Token * var3 = tok - > tokAt ( b ? 16 : 15 ) ;
const Token * any2 = tok - > tokAt ( b ? 20 : 19 ) ;
// Check if all the "%var%" fields are the same and if all the "%any%" are the same..
if ( var1 - > str ( ) = = var2 - > str ( ) & &
var2 - > str ( ) = = var3 - > str ( ) & &
any1 - > str ( ) = = any2 - > str ( ) )
{
2009-03-21 17:58:13 +01:00
redundantIfRemoveError ( tok ) ;
2009-01-26 20:14:46 +01:00
}
tok = Token : : findmatch ( tok - > next ( ) , pattern ) ;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// strtol(str, 0, radix) <- radix must be 0 or 2-36
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : invalidFunctionUsage ( )
2009-01-26 20:14:46 +01:00
{
// strtol and strtoul..
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ( tok - > str ( ) ! = " strtol " ) & & ( tok - > str ( ) ! = " strtoul " ) )
continue ;
// Locate the third parameter of the function call..
int parlevel = 0 ;
int param = 1 ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
2009-07-27 11:24:24 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-01-26 20:14:46 +01:00
+ + parlevel ;
2009-07-27 11:24:24 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-01-26 20:14:46 +01:00
- - parlevel ;
2009-07-27 11:24:24 +02:00
else if ( parlevel = = 1 & & tok2 - > str ( ) = = " , " )
2009-01-26 20:14:46 +01:00
{
+ + param ;
if ( param = = 3 )
{
if ( Token : : Match ( tok2 , " , %num% ) " ) )
{
2009-05-02 10:45:15 +02:00
int radix = MathLib : : toLongNumber ( tok2 - > next ( ) - > str ( ) ) ;
2009-01-26 20:14:46 +01:00
if ( ! ( radix = = 0 | | ( radix > = 2 & & radix < = 36 ) ) )
{
2009-03-21 17:58:13 +01:00
dangerousUsageStrtolError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
}
}
break ;
}
}
}
}
// sprintf|snprintf overlapping data
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Get variable id of target buffer..
unsigned int varid = 0 ;
if ( Token : : Match ( tok , " sprintf|snprintf ( %var% , " ) )
varid = tok - > tokAt ( 2 ) - > varId ( ) ;
else if ( Token : : Match ( tok , " sprintf|snprintf ( %var% . %var% , " ) )
varid = tok - > tokAt ( 4 ) - > varId ( ) ;
if ( varid = = 0 )
continue ;
// goto ","
const Token * tok2 = tok - > tokAt ( 3 ) ;
while ( tok2 & & tok2 - > str ( ) ! = " , " )
tok2 = tok2 - > next ( ) ;
// is any source buffer overlapping the target buffer?
int parlevel = 0 ;
while ( ( tok2 = tok2 - > next ( ) ) ! = NULL )
{
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
- - parlevel ;
if ( parlevel < 0 )
break ;
}
2009-01-27 08:21:52 +01:00
else if ( parlevel = = 0 & & Token : : Match ( tok2 , " , %varid% [,)] " , varid ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
sprintfOverlappingDataError ( tok2 - > next ( ) , tok2 - > next ( ) - > str ( ) ) ;
2009-01-26 20:14:46 +01:00
break ;
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check for unsigned divisions
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkUnsignedDivision ( )
2009-01-26 20:14:46 +01:00
{
2009-09-15 20:46:47 +02:00
if ( ! _settings - > _showAll | | ! _settings - > _checkCodingStyle )
return ;
2009-01-26 20:14:46 +01:00
// Check for "ivar / uvar" and "uvar / ivar"
2009-10-11 16:52:35 +02:00
std : : map < unsigned int , char > varsign ;
2009-01-26 20:14:46 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " [{};(,] %type% %var% [;=,)] " ) )
{
2010-02-14 19:58:17 +01:00
const std : : string type = tok - > strAt ( 1 ) ;
if ( type = = " char " | | type = = " short " | | type = = " int " )
2009-10-11 16:52:35 +02:00
varsign [ tok - > tokAt ( 2 ) - > varId ( ) ] = ' s ' ;
2009-01-26 20:14:46 +01:00
}
else if ( Token : : Match ( tok , " [{};(,] unsigned %type% %var% [;=,)] " ) )
2009-10-11 16:52:35 +02:00
varsign [ tok - > tokAt ( 3 ) - > varId ( ) ] = ' u ' ;
2009-01-26 20:14:46 +01:00
2010-02-12 21:24:06 +01:00
else if ( ! Token : : Match ( tok , " [).] " ) & &
Token : : Match ( tok - > next ( ) , " %var% / %var% " ) & &
tok - > tokAt ( 1 ) - > varId ( ) ! = 0 & &
tok - > tokAt ( 3 ) - > varId ( ) ! = 0 )
2009-01-26 20:14:46 +01:00
{
2009-03-20 18:16:21 +01:00
if ( ErrorLogger : : udivWarning ( * _settings ) )
2009-01-26 20:14:46 +01:00
{
2009-10-11 16:52:35 +02:00
char sign1 = varsign [ tok - > tokAt ( 1 ) - > varId ( ) ] ;
char sign2 = varsign [ tok - > tokAt ( 3 ) - > varId ( ) ] ;
2009-01-26 20:14:46 +01:00
if ( sign1 & & sign2 & & sign1 ! = sign2 )
{
// One of the operands are signed, the other is unsigned..
2009-03-21 17:58:13 +01:00
udivWarning ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-03-17 20:50:06 +01:00
else if ( ! Token : : Match ( tok , " [).] " ) & & Token : : Match ( tok - > next ( ) , " %var% / %num% " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-17 20:50:06 +01:00
if ( tok - > strAt ( 3 ) [ 0 ] = = ' - ' & & ErrorLogger : : udivError ( ) )
2009-01-26 20:14:46 +01:00
{
2009-10-11 16:52:35 +02:00
char sign1 = varsign [ tok - > tokAt ( 1 ) - > varId ( ) ] ;
2009-01-26 20:14:46 +01:00
if ( sign1 = = ' u ' )
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-03-17 20:50:06 +01:00
else if ( Token : : Match ( tok , " [([=*/+-,] %num% / %var% " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-17 20:50:06 +01:00
if ( tok - > strAt ( 1 ) [ 0 ] = = ' - ' & & ErrorLogger : : udivError ( ) )
2009-01-26 20:14:46 +01:00
{
2009-10-11 16:52:35 +02:00
char sign2 = varsign [ tok - > tokAt ( 3 ) - > varId ( ) ] ;
2009-01-26 20:14:46 +01:00
if ( sign2 = = ' u ' )
{
2009-03-21 17:58:13 +01:00
udivError ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
}
//---------------------------------------------------------------------------
2010-02-18 18:45:13 +01:00
//---------------------------------------------------------------------------
// Unreachable code below a 'return'
//---------------------------------------------------------------------------
void CheckOther : : unreachableCode ( )
{
const Token * tok = _tokenizer - > tokens ( ) ;
while ( ( tok = Token : : findmatch ( tok , " [;{}] return " ) ) )
{
// Goto the 'return' token
tok = tok - > next ( ) ;
// Locate the end of the 'return' statement
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
while ( tok & & tok - > next ( ) & & tok - > next ( ) - > str ( ) = = " ; " )
tok = tok - > next ( ) ;
if ( ! tok )
break ;
// If there is a statement below the return it is unreachable
2010-02-18 19:55:47 +01:00
/* original:
if ( ! Token : : Match ( tok , " ; case|default|}|# " ) & &
! Token : : Match ( tok , " ; %var% : " ) & &
! Token : : simpleMatch ( tok , " ; break " ) )
*/
2010-02-18 18:45:13 +01:00
if ( Token : : simpleMatch ( tok , " ; break " ) )
{
unreachableCodeError ( tok - > next ( ) ) ;
}
}
}
void CheckOther : : unreachableCodeError ( const Token * tok )
{
reportError ( tok , Severity : : style , " unreachableCode " , " Unreachable code below a 'return' " ) ;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
static bool isOp ( const Token * tok )
{
return bool ( tok & &
( tok - > str ( ) = = " && " | |
tok - > str ( ) = = " || " | |
tok - > str ( ) = = " == " | |
tok - > str ( ) = = " != " | |
tok - > str ( ) = = " < " | |
tok - > str ( ) = = " <= " | |
tok - > str ( ) = = " > " | |
tok - > str ( ) = = " >= " | |
tok - > str ( ) = = " << " | |
Token : : Match ( tok , " [+-*/%&!~|^,[])?:] " ) ) ) ;
}
2010-02-21 07:05:44 +01:00
/** Store information about variable usage */
class VariableUsage
{
public :
VariableUsage ( )
{
declare = false ;
read = false ;
write = false ;
}
/** variable is used.. set both read+write */
void use ( )
{
read = true ;
write = true ;
}
/** is variable unused? */
bool unused ( ) const
{
return ( read = = false & & write = = false ) ;
}
bool declare ;
bool read ;
bool write ;
} ;
2010-02-18 18:45:13 +01:00
void CheckOther : : functionVariableUsage ( )
{
// Parse all executing scopes..
2010-02-21 08:02:44 +01:00
for ( const Token * token = Token : : findmatch ( _tokenizer - > tokens ( ) , " ) const| { " ) ; token ; )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
// goto "{"
while ( token - > str ( ) ! = " { " )
token = token - > next ( ) ;
// First token for the current scope..
const Token * const tok1 = token ;
// Find next scope that will be checked next time..
token = Token : : findmatch ( token - > link ( ) , " ) const| { " ) ;
2010-02-18 18:45:13 +01:00
// Varname, usage {1=declare, 2=read, 4=write}
2010-02-21 07:05:44 +01:00
std : : map < std : : string , VariableUsage > varUsage ;
2010-02-18 18:45:13 +01:00
2010-02-21 08:02:44 +01:00
unsigned int indentlevel = 0 ;
for ( const Token * tok = tok1 ; tok ; tok = tok - > next ( ) )
2010-02-18 18:45:13 +01:00
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
2010-02-21 08:02:44 +01:00
if ( indentlevel < = 1 )
2010-02-18 18:45:13 +01:00
break ;
2010-02-21 08:02:44 +01:00
- - indentlevel ;
2010-02-18 18:45:13 +01:00
}
else if ( Token : : Match ( tok , " struct|union|class { " ) | |
Token : : Match ( tok , " struct|union|class %type% { " ) )
{
while ( tok - > str ( ) ! = " { " )
tok = tok - > next ( ) ;
2010-02-21 08:02:44 +01:00
tok = tok - > link ( ) ;
2010-02-18 18:45:13 +01:00
if ( ! tok )
break ;
}
2010-02-21 07:05:44 +01:00
if ( Token : : Match ( tok , " [;{}] %type% %var% ;|= " ) & & tok - > next ( ) - > isStandardType ( ) )
varUsage [ tok - > strAt ( 2 ) ] . declare = true ;
2010-02-18 18:45:13 +01:00
2010-02-21 07:05:44 +01:00
else if ( Token : : Match ( tok , " [;{}] %type% * %var% ;|= " ) & & tok - > next ( ) - > isStandardType ( ) )
varUsage [ tok - > strAt ( 3 ) ] . declare = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " delete|return %var% " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . read = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " %var% = " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > str ( ) ] . write = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " else %var% = " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . write = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " >>|& %var% " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . use ( ) ; // use = read + write
2010-02-18 18:45:13 +01:00
2010-02-21 08:02:44 +01:00
else if ( Token : : Match ( tok , " [(,] %var% [,)] " ) )
varUsage [ tok - > strAt ( 1 ) ] . use ( ) ; // use = read + write
2010-02-18 18:45:13 +01:00
else if ( ( Token : : Match ( tok , " [(=&!] " ) | | isOp ( tok ) ) & & Token : : Match ( tok - > next ( ) , " %var% " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . read = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " -=|+=|*=|/=|&=|^= %var% " ) | | Token : : Match ( tok , " |= %var% " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . read = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " %var% " ) & & ( tok - > next ( ) - > str ( ) = = " ) " | | isOp ( tok - > next ( ) ) ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > str ( ) ] . read = true ;
2010-02-18 18:45:13 +01:00
else if ( Token : : Match ( tok , " ; %var% ; " ) )
2010-02-21 07:05:44 +01:00
varUsage [ tok - > strAt ( 1 ) ] . read = true ;
2010-02-18 18:45:13 +01:00
}
// Check usage of all variables in the current scope..
2010-02-21 07:05:44 +01:00
for ( std : : map < std : : string , VariableUsage > : : const_iterator it = varUsage . begin ( ) ; it ! = varUsage . end ( ) ; + + it )
2010-02-18 18:45:13 +01:00
{
2010-02-21 07:05:44 +01:00
const std : : string & varname = it - > first ;
const VariableUsage & usage = it - > second ;
2010-02-18 18:45:13 +01:00
if ( ! std : : isalpha ( varname [ 0 ] ) )
continue ;
2010-02-21 07:05:44 +01:00
if ( ! ( usage . declare ) )
2010-02-18 18:45:13 +01:00
continue ;
2010-02-21 07:05:44 +01:00
if ( usage . unused ( ) )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
unusedVariableError ( tok1 , varname ) ;
2010-02-18 18:45:13 +01:00
}
2010-02-21 07:05:44 +01:00
else if ( ! ( usage . read ) )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
unreadVariableError ( tok1 , varname ) ;
2010-02-18 18:45:13 +01:00
}
2010-02-21 07:05:44 +01:00
else if ( ! ( usage . write ) )
2010-02-18 18:45:13 +01:00
{
2010-02-21 08:02:44 +01:00
unassignedVariableError ( tok1 , varname ) ;
2010-02-18 18:45:13 +01:00
}
}
}
}
void CheckOther : : unusedVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unusedVariable " , " Unused variable: " + varname ) ;
}
void CheckOther : : unreadVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unreadVariable " , " Variable ' " + varname + " ' is assigned a value that is never used " ) ;
}
void CheckOther : : unassignedVariableError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : style , " unassignedVariable " , " Variable ' " + varname + " ' is not assigned a value " ) ;
}
//---------------------------------------------------------------------------
2009-01-26 20:14:46 +01:00
//---------------------------------------------------------------------------
// Check scope of variables..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkVariableScope ( )
2009-01-26 20:14:46 +01:00
{
// Walk through all tokens..
bool func = false ;
int indentlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Skip class and struct declarations..
if ( ( tok - > str ( ) = = " class " ) | | ( tok - > str ( ) = = " struct " ) )
{
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
{
2009-10-06 17:45:28 +02:00
tok = tok2 - > link ( ) ;
2009-01-26 20:14:46 +01:00
break ;
}
if ( Token : : Match ( tok2 , " [,);] " ) )
{
break ;
}
}
if ( ! tok )
break ;
}
2009-10-06 17:45:28 +02:00
else if ( tok - > str ( ) = = " { " )
2009-01-26 20:14:46 +01:00
{
+ + indentlevel ;
}
2009-10-06 17:45:28 +02:00
else if ( tok - > str ( ) = = " } " )
2009-01-26 20:14:46 +01:00
{
- - indentlevel ;
if ( indentlevel = = 0 )
func = false ;
}
2009-05-21 17:55:52 +02:00
if ( indentlevel = = 0 & & Token : : simpleMatch ( tok , " ) { " ) )
2009-01-26 20:14:46 +01:00
{
func = true ;
}
if ( indentlevel > 0 & & func & & Token : : Match ( tok , " [{};] " ) )
{
// First token of statement..
const Token * tok1 = tok - > next ( ) ;
if ( ! tok1 )
continue ;
if ( ( tok1 - > str ( ) = = " return " ) | |
2009-03-24 20:59:56 +01:00
( tok1 - > str ( ) = = " throw " ) | |
2009-01-26 20:14:46 +01:00
( tok1 - > str ( ) = = " delete " ) | |
( tok1 - > str ( ) = = " goto " ) | |
( tok1 - > str ( ) = = " else " ) )
continue ;
// Variable declaration?
2009-09-17 21:05:12 +02:00
if ( Token : : Match ( tok1 , " %type% %var% ; %var% = %num% ; " ) )
2009-08-16 21:12:57 +02:00
{
// Tokenizer modify "int i = 0;" to "int i; i = 0;",
// so to handle this situation we just skip
// initialization (see ticket #272).
const unsigned int firstVarId = tok1 - > next ( ) - > varId ( ) ;
const unsigned int secondVarId = tok1 - > tokAt ( 3 ) - > varId ( ) ;
if ( firstVarId > 0 & & firstVarId = = secondVarId )
{
lookupVar ( tok1 - > tokAt ( 6 ) , tok1 - > strAt ( 1 ) ) ;
}
}
else if ( Token : : Match ( tok1 , " %type% %var% [;=] " ) )
2009-01-26 20:14:46 +01:00
{
2009-07-05 22:16:43 +02:00
lookupVar ( tok1 , tok1 - > strAt ( 1 ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
2010-02-14 19:58:17 +01:00
void CheckOther : : lookupVar ( const Token * tok1 , const std : : string & varname )
2009-01-26 20:14:46 +01:00
{
const Token * tok = tok1 ;
// Skip the variable declaration..
2009-07-27 11:24:24 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
2009-01-26 20:14:46 +01:00
tok = tok - > next ( ) ;
// Check if the variable is used in this indentlevel..
2010-01-21 18:50:56 +01:00
bool used1 = false ; // used in one sub-scope -> reducable
bool used2 = false ; // used in more sub-scopes -> not reducable
2009-01-26 20:14:46 +01:00
int indentlevel = 0 ;
int parlevel = 0 ;
2010-01-21 18:50:56 +01:00
bool for_or_while = false ; // is sub-scope a "for/while/etc". anything that is not "if"
2009-06-12 16:17:51 +02:00
while ( tok )
2009-01-26 20:14:46 +01:00
{
if ( tok - > str ( ) = = " { " )
{
+ + indentlevel ;
}
else if ( tok - > str ( ) = = " } " )
{
2009-06-12 16:17:51 +02:00
if ( indentlevel = = 0 )
break ;
2009-01-26 20:14:46 +01:00
- - indentlevel ;
if ( indentlevel = = 0 )
{
2010-01-21 18:50:56 +01:00
if ( for_or_while & & used2 )
2009-01-26 20:14:46 +01:00
return ;
2010-01-21 18:50:56 +01:00
used2 | = used1 ;
used1 = false ;
2009-01-26 20:14:46 +01:00
}
}
else if ( tok - > str ( ) = = " ( " )
{
+ + parlevel ;
}
else if ( tok - > str ( ) = = " ) " )
{
- - parlevel ;
}
2009-05-27 19:38:26 +02:00
// Bail out if references are used
else if ( Token : : simpleMatch ( tok , ( std : : string ( " & " ) + varname ) . c_str ( ) ) )
{
return ;
}
2009-01-26 20:14:46 +01:00
else if ( tok - > str ( ) = = varname )
{
2010-01-21 18:50:56 +01:00
if ( indentlevel = = 0 )
return ;
used1 = true ;
if ( for_or_while & & ! Token : : simpleMatch ( tok - > next ( ) , " = " ) )
used2 = true ;
if ( used1 & & used2 )
2009-01-26 20:14:46 +01:00
return ;
}
else if ( indentlevel = = 0 )
{
2009-09-29 23:56:43 +02:00
// %unknown% ( %any% ) {
// If %unknown% is anything except if, we assume
// that it is a for or while loop or a macro hiding either one
if ( Token : : simpleMatch ( tok - > next ( ) , " ( " ) & &
2010-01-21 18:50:56 +01:00
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " ) )
2009-09-29 23:56:43 +02:00
{
if ( tok - > str ( ) ! = " if " )
for_or_while = true ;
}
if ( Token : : simpleMatch ( tok , " do { " ) )
2009-01-26 20:14:46 +01:00
for_or_while = true ;
2009-09-29 23:56:43 +02:00
2009-01-26 20:14:46 +01:00
if ( parlevel = = 0 & & ( tok - > str ( ) = = " ; " ) )
for_or_while = false ;
}
tok = tok - > next ( ) ;
}
2009-06-12 16:17:51 +02:00
// Warning if this variable:
// * not used in this indentlevel
// * used in lower indentlevel
2010-01-21 18:50:56 +01:00
if ( used1 | | used2 )
2009-06-12 16:17:51 +02:00
variableScopeError ( tok1 , varname ) ;
2009-01-26 20:14:46 +01:00
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check for constant function parameters
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkConstantFunctionParameter ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " [,(] const std :: %type% %var% [,)] " ) )
{
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 5 ) ) ;
2009-01-26 20:14:46 +01:00
}
2009-10-05 10:59:28 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 8 ) ) ;
}
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 10 ) ) ;
}
2009-10-06 23:04:54 +02:00
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% , std :: %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 14 ) ) ;
}
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% , std :: %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 12 ) ) ;
}
else if ( Token : : Match ( tok , " [,(] const std :: %type% < std :: %type% , %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 12 ) ) ;
}
else if ( Token : : Match ( tok , " [,(] const std :: %type% < %type% , %type% > %var% [,)] " ) )
{
passedByValueError ( tok , tok - > strAt ( 10 ) ) ;
}
2009-01-26 20:14:46 +01:00
else if ( Token : : Match ( tok , " [,(] const %type% %var% [,)] " ) )
{
// Check if type is a struct or class.
const std : : string pattern ( std : : string ( " class|struct " ) + tok - > strAt ( 2 ) ) ;
if ( Token : : findmatch ( _tokenizer - > tokens ( ) , pattern . c_str ( ) ) )
{
2009-03-21 17:58:13 +01:00
passedByValueError ( tok , tok - > strAt ( 3 ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Check that all struct members are used
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkStructMemberUsage ( )
2009-01-26 20:14:46 +01:00
{
2010-02-14 19:58:17 +01:00
std : : string structname ;
2009-01-26 20:14:46 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > fileIndex ( ) ! = 0 )
continue ;
if ( Token : : Match ( tok , " struct|union %type% { " ) )
{
structname = tok - > strAt ( 1 ) ;
// Bail out if struct/union contain any functions
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ( " )
{
2010-02-14 19:58:17 +01:00
structname = " " ;
2009-01-26 20:14:46 +01:00
break ;
}
if ( tok2 - > str ( ) = = " } " )
break ;
}
2009-10-17 17:36:55 +02:00
// Bail out if some data is casted to struct..
2009-10-17 19:31:14 +02:00
const std : : string s ( " ( struct| " + tok - > next ( ) - > str ( ) + " * ) & %var% [ " ) ;
2009-10-17 17:36:55 +02:00
if ( Token : : findmatch ( tok , s . c_str ( ) ) )
2010-02-14 19:58:17 +01:00
structname = " " ;
2009-01-26 20:14:46 +01:00
}
if ( tok - > str ( ) = = " } " )
2010-02-14 19:58:17 +01:00
structname = " " ;
2009-01-26 20:14:46 +01:00
2010-02-14 19:58:17 +01:00
if ( ! structname . empty ( ) & & Token : : Match ( tok , " [{;] " ) )
2009-01-26 20:14:46 +01:00
{
2010-02-14 19:58:17 +01:00
std : : string varname ;
2009-01-26 20:14:46 +01:00
if ( Token : : Match ( tok - > next ( ) , " %type% %var% [;[] " ) )
varname = tok - > strAt ( 2 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% %var% [ ; [ ] " ))
varname = tok - > strAt ( 3 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% * %var% [ ; [ ] " ))
varname = tok - > strAt ( 3 ) ;
else if ( Token : : Match ( tok - > next ( ) , " %type% %type% * %var% [ ; [ ] " ))
varname = tok - > strAt ( 4 ) ;
else
continue ;
2010-02-14 19:58:17 +01:00
const std : : string usagePattern ( " . " + varname ) ;
2009-01-26 20:14:46 +01:00
bool used = false ;
for ( const Token * tok2 = _tokenizer - > tokens ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( Token : : simpleMatch ( tok2 , usagePattern . c_str ( ) ) )
{
used = true ;
break ;
}
}
if ( ! used )
{
2009-03-21 17:58:13 +01:00
unusedStructMemberError ( tok - > next ( ) , structname , varname ) ;
2009-01-26 20:14:46 +01:00
}
}
}
}
//---------------------------------------------------------------------------
// Check usage of char variables..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkCharVariable ( )
2009-01-26 20:14:46 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Declaring the variable..
2009-02-04 18:12:53 +01:00
if ( Token : : Match ( tok , " [{};(,] signed| char %var% [;=,)] " ) )
2009-01-26 20:14:46 +01:00
{
// Set tok to point to the variable name
tok = tok - > tokAt ( 2 ) ;
2009-02-04 18:12:53 +01:00
if ( tok - > str ( ) = = " char " )
tok = tok - > next ( ) ;
2009-01-26 20:14:46 +01:00
// Check usage of char variable..
int indentlevel = 0 ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
- - indentlevel ;
if ( indentlevel < = 0 )
break ;
}
2009-03-23 19:04:51 +01:00
else if ( tok2 - > str ( ) = = " return " )
continue ;
2009-01-26 20:14:46 +01:00
std : : string temp = " %var% [ " + tok - > str ( ) + " ] " ;
if ( ( tok2 - > str ( ) ! = " . " ) & & Token : : Match ( tok2 - > next ( ) , temp . c_str ( ) ) )
{
2009-03-21 17:58:13 +01:00
charArrayIndexError ( tok2 - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
break ;
}
2009-06-20 19:24:58 +02:00
if ( Token : : Match ( tok2 , " [;{}] %var% = %any% [&|] %any% ; " ) )
2009-01-26 20:14:46 +01:00
{
2009-06-20 19:24:58 +02:00
// is the char variable used in the calculation?
if ( tok2 - > tokAt ( 3 ) - > varId ( ) ! = tok - > varId ( ) & & tok2 - > tokAt ( 5 ) - > varId ( ) ! = tok - > varId ( ) )
continue ;
// it's ok with a bitwise and where the other operand is 0xff or less..
if ( std : : string ( tok2 - > strAt ( 4 ) ) = = " & " )
{
if ( tok2 - > tokAt ( 3 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 3 ) ) )
continue ;
if ( tok2 - > tokAt ( 5 ) - > isNumber ( ) & & MathLib : : isGreater ( " 0x100 " , tok2 - > strAt ( 5 ) ) )
continue ;
}
// is the result stored in a short|int|long?
if ( ! Token : : findmatch ( _tokenizer - > tokens ( ) , " short|int|long %varid% " , tok2 - > next ( ) - > varId ( ) ) )
continue ;
// This is an error..
2009-03-21 17:58:13 +01:00
charBitOpError ( tok2 ) ;
2009-01-26 20:14:46 +01:00
break ;
}
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Incomplete statement..
//---------------------------------------------------------------------------
2009-07-05 22:16:43 +02:00
void CheckOther : : checkIncompleteStatement ( )
2009-01-26 20:14:46 +01:00
{
int parlevel = 0 ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " ( " )
+ + parlevel ;
else if ( tok - > str ( ) = = " ) " )
- - parlevel ;
if ( parlevel ! = 0 )
continue ;
2009-05-21 17:55:52 +02:00
if ( Token : : simpleMatch ( tok , " = { " ) )
2009-02-11 16:17:13 +01:00
{
2009-02-12 13:59:43 +01:00
/* We are in an assignment, so it's not a statement.
* Skip until " ; " */
2009-07-27 11:24:24 +02:00
while ( tok - > str ( ) ! = " ; " )
2009-02-12 13:59:43 +01:00
{
int level = 0 ;
do
{
if ( tok - > str ( ) = = " ( " | | tok - > str ( ) = = " { " )
+ + level ;
else if ( tok - > str ( ) = = " ) " | | tok - > str ( ) = = " } " )
- - level ;
tok = tok - > next ( ) ;
if ( tok = = NULL )
return ;
}
while ( level > 0 ) ;
}
2009-02-11 16:17:13 +01:00
continue ;
}
2009-02-05 19:57:53 +01:00
if ( Token : : Match ( tok , " [;{}] %str% " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) , " [,}] " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
constStatementError ( tok - > next ( ) , " string " ) ;
2009-01-26 20:14:46 +01:00
}
2009-02-05 19:57:53 +01:00
if ( Token : : Match ( tok , " [;{}] %num% " ) & & ! Token : : Match ( tok - > tokAt ( 2 ) , " [,}] " ) )
2009-01-26 20:14:46 +01:00
{
2009-03-21 17:58:13 +01:00
constStatementError ( tok - > next ( ) , " numeric " ) ;
2009-01-26 20:14:46 +01:00
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// str plus char
//---------------------------------------------------------------------------
void CheckOther : : strPlusChar ( )
{
2010-02-01 19:46:51 +01:00
bool charVars [ 10000 ] = { 0 } ;
2009-01-26 20:14:46 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2010-02-01 19:46:51 +01:00
// Declaring char variable..
2010-02-07 21:44:11 +01:00
if ( Token : : Match ( tok , " char|int|short %var% [;=] " ) )
2009-01-26 20:14:46 +01:00
{
unsigned int varid = tok - > next ( ) - > varId ( ) ;
if ( varid > 0 & & varid < 10000 )
2010-02-01 19:46:51 +01:00
charVars [ varid ] = true ;
2009-01-26 20:14:46 +01:00
}
2010-02-01 19:46:51 +01:00
//
else if ( Token : : Match ( tok , " [=(] %str% + %any% " ) )
2009-01-26 20:14:46 +01:00
{
// char constant..
2010-02-14 19:58:17 +01:00
const std : : string s = tok - > strAt ( 3 ) ;
if ( s [ 0 ] = = ' \' ' )
2009-03-21 17:58:13 +01:00
strPlusChar ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
// char variable..
unsigned int varid = tok - > tokAt ( 3 ) - > varId ( ) ;
2010-02-01 19:46:51 +01:00
if ( varid > 0 & & varid < 10000 & & charVars [ varid ] )
strPlusChar ( tok - > next ( ) ) ;
2009-01-26 20:14:46 +01:00
}
}
}
2009-02-04 19:49:19 +01:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointerAfterLoop ( )
2009-03-27 17:19:34 +01:00
{
// Locate insufficient null-pointer handling after loop
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ! Token : : Match ( tok , " while ( %var% ) " ) )
continue ;
const unsigned int varid ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok - > strAt ( 2 ) ) ;
2009-03-27 17:19:34 +01:00
// Locate the end of the while loop..
const Token * tok2 = tok - > tokAt ( 4 ) ;
2009-08-17 22:23:37 +02:00
if ( tok2 - > str ( ) = = " { " )
tok2 = tok2 - > link ( ) ;
else
2009-03-27 17:19:34 +01:00
{
2009-08-17 22:23:37 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
tok2 = tok2 - > next ( ) ;
2009-03-27 17:19:34 +01:00
}
// Goto next token
2009-08-17 22:23:37 +02:00
if ( tok2 )
tok2 = tok2 - > next ( ) ;
2009-03-27 17:19:34 +01:00
// Check if the variable is dereferenced..
while ( tok2 )
{
2009-10-05 13:46:38 +02:00
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " break " )
2009-03-27 17:19:34 +01:00
break ;
if ( tok2 - > varId ( ) = = varid )
{
if ( tok2 - > next ( ) - > str ( ) = = " . " | | Token : : Match ( tok2 - > next ( ) , " = %varid% . " , varid ) )
2009-05-10 08:43:16 +02:00
{
// Is this variable a pointer?
2009-10-08 10:55:37 +02:00
const Token * tok3 = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid ) ;
2009-05-10 08:43:16 +02:00
if ( ! tok3 )
break ;
if ( ! tok3 - > previous ( ) | |
Token : : Match ( tok3 - > previous ( ) , " [({};] " ) | |
tok3 - > previous ( ) - > isName ( ) )
{
2009-08-11 17:18:01 +02:00
nullPointerError ( tok2 , varname ) ;
2009-05-10 08:43:16 +02:00
}
}
2009-03-27 17:19:34 +01:00
break ;
}
tok2 = tok2 - > next ( ) ;
}
}
2009-10-11 17:10:20 +02:00
}
2009-07-20 18:53:41 +02:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointerLinkedList ( )
{
2009-07-31 10:49:43 +02:00
// looping through items in a linked list in a inner loop..
for ( const Token * tok1 = _tokenizer - > tokens ( ) ; tok1 ; tok1 = tok1 - > next ( ) )
{
// search for a "for" token..
if ( ! Token : : simpleMatch ( tok1 , " for ( " ) )
continue ;
if ( ! Token : : simpleMatch ( tok1 - > next ( ) - > link ( ) , " ) { " ) )
continue ;
// is there any dereferencing occuring in the for statement..
unsigned int parlevel2 = 1 ;
for ( const Token * tok2 = tok1 - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
// Parantheses..
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel2 ;
else if ( tok2 - > str ( ) = = " ) " )
{
if ( parlevel2 < = 1 )
break ;
- - parlevel2 ;
}
// Dereferencing a variable inside the "for" parantheses..
else if ( Token : : Match ( tok2 , " %var% . %var% " ) )
{
const unsigned int varid ( tok2 - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
2009-08-01 11:30:37 +02:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " %varid% ? " , varid ) )
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok2 - > str ( ) ) ;
2009-07-31 10:49:43 +02:00
// Check usage of dereferenced variable in the loop..
unsigned int indentlevel3 = 0 ;
for ( const Token * tok3 = tok1 - > next ( ) - > link ( ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel3 ;
else if ( tok3 - > str ( ) = = " } " )
{
if ( indentlevel3 < = 1 )
break ;
- - indentlevel3 ;
}
else if ( Token : : Match ( tok3 , " while ( %varid% &&|) " , varid ) )
{
// Make sure there is a "break" to prevent segmentation faults..
unsigned int indentlevel4 = indentlevel3 ;
2009-10-07 22:38:21 +02:00
for ( const Token * tok4 = tok3 - > next ( ) - > link ( ) ; tok4 ; tok4 = tok4 - > next ( ) )
2009-07-31 10:49:43 +02:00
{
if ( tok4 - > str ( ) = = " { " )
+ + indentlevel4 ;
else if ( tok4 - > str ( ) = = " } " )
{
if ( indentlevel4 < = 1 )
{
2009-10-08 10:55:37 +02:00
// Is this variable a pointer?
const Token * tempTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid ) ;
if ( tempTok )
2010-02-28 07:26:50 +01:00
nullPointerError ( tok1 , varname , tok3 - > linenr ( ) ) ;
2009-10-08 10:55:37 +02:00
2009-07-31 10:49:43 +02:00
break ;
}
- - indentlevel4 ;
}
else if ( tok4 - > str ( ) = = " break " )
break ;
}
}
}
}
}
}
2009-10-11 17:10:20 +02:00
}
void CheckOther : : nullPointerStructByDeRefAndChec ( )
{
2009-07-31 10:49:43 +02:00
2009-07-23 14:13:46 +02:00
// Dereferencing a struct pointer and then checking if it's NULL..
2009-07-20 18:53:41 +02:00
for ( const Token * tok1 = _tokenizer - > tokens ( ) ; tok1 ; tok1 = tok1 - > next ( ) )
{
2009-07-20 19:30:33 +02:00
if ( Token : : Match ( tok1 , " [{};] %var% = %var% . %var% " ) )
2009-07-20 18:53:41 +02:00
{
2009-07-20 19:30:33 +02:00
if ( std : : string ( tok1 - > strAt ( 1 ) ) = = tok1 - > strAt ( 3 ) )
continue ;
tok1 = tok1 - > tokAt ( 3 ) ;
2009-07-21 17:00:11 +02:00
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
if ( varid1 = = 0 )
2009-07-20 19:10:33 +02:00
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok1 - > str ( ) ) ;
2009-07-23 19:59:29 +02:00
// Checking if the struct pointer is non-null before the assignment..
{
const Token * tok2 = _tokenizer - > tokens ( ) ;
while ( tok2 )
{
if ( tok2 = = tok1 )
break ;
if ( Token : : Match ( tok2 , " if|while ( !| %varid% ) " , varid1 ) )
break ;
tok2 = tok2 - > next ( ) ;
}
if ( tok2 ! = tok1 )
continue ;
}
2009-07-20 18:53:41 +02:00
unsigned int indentlevel2 = 0 ;
for ( const Token * tok2 = tok1 - > tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
2009-07-20 19:30:33 +02:00
2009-07-20 18:53:41 +02:00
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel2 = = 0 )
break ;
- - indentlevel2 ;
}
2009-07-20 19:30:33 +02:00
2009-08-12 18:54:52 +02:00
// goto destination..
else if ( tok2 - > isName ( ) & & Token : : simpleMatch ( tok2 - > next ( ) , " : " ) )
break ;
2009-07-21 12:09:58 +02:00
// Reassignment of the struct
else if ( tok2 - > varId ( ) = = varid1 )
{
2009-07-27 11:25:41 +02:00
if ( tok2 - > next ( ) - > str ( ) = = " = " )
2009-07-21 12:09:58 +02:00
break ;
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [,(] & " ) )
break ;
}
2009-07-29 11:17:22 +02:00
// Loop..
/** @todo don't bail out if the variable is not used in the loop */
else if ( tok2 - > str ( ) = = " do " )
break ;
2009-07-21 12:09:58 +02:00
// return at base level => stop checking
else if ( indentlevel2 = = 0 & & tok2 - > str ( ) = = " return " )
2009-07-20 19:59:55 +02:00
break ;
2009-07-21 17:00:11 +02:00
else if ( Token : : Match ( tok2 , " if ( !| %varid% ) " , varid1 ) )
2009-07-20 18:53:41 +02:00
{
2009-10-08 10:55:37 +02:00
// Is this variable a pointer?
const Token * tempTok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %type% * %varid% [;)=] " , varid1 ) ;
if ( tempTok )
nullPointerError ( tok1 , varname , tok2 - > linenr ( ) ) ;
2009-07-21 17:00:11 +02:00
break ;
2009-07-20 18:53:41 +02:00
}
}
}
}
2009-07-23 14:13:46 +02:00
2009-10-11 17:10:20 +02:00
}
void CheckOther : : nullPointerByDeRefAndChec ( )
{
2009-07-23 14:13:46 +02:00
// Dereferencing a pointer and then checking if it's NULL..
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " if " & & Token : : Match ( tok - > previous ( ) , " ; if ( ! %var% ) " ) )
{
const unsigned int varid ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
2009-08-11 17:18:01 +02:00
const std : : string varname ( tok - > strAt ( 3 ) ) ;
2009-07-25 20:36:02 +02:00
const Token * decltok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) ;
if ( ! Token : : Match ( decltok - > tokAt ( - 3 ) , " [;,(] %var% * " ) )
continue ;
for ( const Token * tok1 = tok - > previous ( ) ; tok1 & & tok1 ! = decltok ; tok1 = tok1 - > previous ( ) )
2009-07-23 14:13:46 +02:00
{
if ( tok1 - > varId ( ) = = varid )
{
2009-08-28 08:48:37 +02:00
if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " [=;{}] * " ) )
2009-07-23 14:13:46 +02:00
{
2009-08-11 17:18:01 +02:00
nullPointerError ( tok1 , varname ) ;
2009-07-23 14:13:46 +02:00
break ;
}
2009-07-23 19:02:14 +02:00
else if ( tok1 - > previous ( ) & & tok1 - > previous ( ) - > str ( ) = = " & " )
{
break ;
}
2009-07-23 14:13:46 +02:00
else if ( tok1 - > next ( ) & & tok1 - > next ( ) - > str ( ) = = " = " )
{
break ;
}
}
else if ( tok1 - > str ( ) = = " { " ||
tok1 - > str ( ) = = " } " )
break ;
2009-08-12 18:54:52 +02:00
// goto destination..
else if ( tok1 - > isName ( ) & & Token : : simpleMatch ( tok1 - > next ( ) , " : " ) )
break ;
2009-07-23 14:13:46 +02:00
}
}
}
2009-03-27 17:19:34 +01:00
}
2009-10-19 17:32:43 +02:00
2009-10-11 17:10:20 +02:00
void CheckOther : : nullPointer ( )
{
nullPointerAfterLoop ( ) ;
nullPointerLinkedList ( ) ;
nullPointerStructByDeRefAndChec ( ) ;
nullPointerByDeRefAndChec ( ) ;
}
2009-03-27 17:19:34 +01:00
2009-12-06 18:41:28 +01:00
2010-01-11 22:28:07 +01:00
2009-12-23 19:51:32 +01:00
/**
* \ brief parse a function call and extract information about variable usage
* \ param tok first token
* \ param var variables that the function read / write .
* \ param value 0 = > invalid with null pointers as parameter .
* 1 - . . = > invalid with uninitialized data .
*/
static void parseFunctionCall ( const Token & tok , std : : list < const Token * > & var , unsigned char value )
{
// standard functions that dereference first parameter..
// both uninitialized data and null pointers are invalid.
static std : : set < std : : string > functionNames1 ;
if ( functionNames1 . empty ( ) )
{
functionNames1 . insert ( " memchr " ) ;
functionNames1 . insert ( " memcmp " ) ;
functionNames1 . insert ( " strcat " ) ;
functionNames1 . insert ( " strncat " ) ;
functionNames1 . insert ( " strchr " ) ;
functionNames1 . insert ( " strrchr " ) ;
functionNames1 . insert ( " strcmp " ) ;
functionNames1 . insert ( " strncmp " ) ;
functionNames1 . insert ( " strdup " ) ;
functionNames1 . insert ( " strlen " ) ;
functionNames1 . insert ( " strstr " ) ;
}
// standard functions that dereference second parameter..
// both uninitialized data and null pointers are invalid.
static std : : set < std : : string > functionNames2 ;
if ( functionNames2 . empty ( ) )
{
functionNames2 . insert ( " memcmp " ) ;
functionNames2 . insert ( " memcpy " ) ;
functionNames2 . insert ( " memmove " ) ;
functionNames2 . insert ( " strcat " ) ;
functionNames2 . insert ( " strncat " ) ;
functionNames2 . insert ( " strcmp " ) ;
functionNames2 . insert ( " strncmp " ) ;
functionNames2 . insert ( " strcpy " ) ;
functionNames2 . insert ( " strncpy " ) ;
functionNames2 . insert ( " strstr " ) ;
}
// 1st parameter..
if ( Token : : Match ( & tok , " %var% ( %var% ,|) " ) & & tok . tokAt ( 2 ) - > varId ( ) > 0 )
{
if ( functionNames1 . find ( tok . str ( ) ) ! = functionNames1 . end ( ) )
var . push_back ( tok . tokAt ( 2 ) ) ;
else if ( value = = 0 & & Token : : Match ( & tok , " memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf " ) )
var . push_back ( tok . tokAt ( 2 ) ) ;
2009-12-27 18:00:43 +01:00
else if ( Token : : simpleMatch ( & tok , " fflush " ) )
2009-12-23 19:51:32 +01:00
var . push_back ( tok . tokAt ( 2 ) ) ;
}
// 2nd parameter..
if ( Token : : Match ( & tok , " %var% ( %any% , %var% ,|) " ) & & tok . tokAt ( 4 ) - > varId ( ) > 0 )
{
if ( functionNames2 . find ( tok . str ( ) ) ! = functionNames2 . end ( ) )
var . push_back ( tok . tokAt ( 4 ) ) ;
}
}
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
class CheckNullpointer : public ExecutionPath
{
public :
// Startup constructor
2009-12-21 18:17:35 +01:00
CheckNullpointer ( Check * c ) : ExecutionPath ( c , 0 ) , null ( false )
2009-12-06 18:41:28 +01:00
{
}
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
private :
2009-12-20 19:44:32 +01:00
// Create checking of specific variable:
2009-12-21 18:17:35 +01:00
CheckNullpointer ( Check * c , const unsigned int id , const std : : string & name )
: ExecutionPath ( c , id ) ,
2009-12-20 19:44:32 +01:00
varname ( name ) ,
2009-12-21 18:17:35 +01:00
null ( false )
2009-12-20 19:44:32 +01:00
{
}
2009-12-06 18:41:28 +01:00
ExecutionPath * copy ( )
{
return new CheckNullpointer ( * this ) ;
}
2009-10-29 21:34:43 +01:00
2009-12-06 20:34:02 +01:00
/* no implementation */
void operator = ( const CheckNullpointer & ) ;
2009-12-20 19:44:32 +01:00
const std : : string varname ;
2009-12-06 18:41:28 +01:00
bool null ;
2009-10-29 21:34:43 +01:00
2009-12-20 19:44:32 +01:00
static void setnull ( std : : list < ExecutionPath * > & checks , const unsigned int varid )
2009-12-06 18:41:28 +01:00
{
std : : list < ExecutionPath * > : : iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
2009-12-20 19:44:32 +01:00
{
CheckNullpointer * c = dynamic_cast < CheckNullpointer * > ( * it ) ;
if ( c & & c - > varId = = varid )
c - > null = true ;
}
2009-12-06 18:41:28 +01:00
}
2009-10-29 21:34:43 +01:00
2009-12-20 19:44:32 +01:00
static void dereference ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
2009-12-06 18:41:28 +01:00
{
2009-12-20 19:44:32 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
2009-12-06 18:41:28 +01:00
std : : list < ExecutionPath * > : : iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
2009-12-20 19:44:32 +01:00
CheckNullpointer * c = dynamic_cast < CheckNullpointer * > ( * it ) ;
if ( c & & c - > varId = = varid & & c - > null )
2009-12-06 18:41:28 +01:00
{
foundError = true ;
2009-12-21 18:17:35 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
if ( checkOther )
{
checkOther - > nullPointerError ( tok , c - > varname ) ;
break ;
}
2009-12-20 19:44:32 +01:00
}
}
}
2009-12-06 18:41:28 +01:00
const Token * parse ( const Token & tok , bool & foundError , std : : list < ExecutionPath * > & checks ) const
{
2009-12-20 19:44:32 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% * %var% ; " ) )
{
const Token * vartok = tok . tokAt ( 2 ) ;
if ( vartok - > varId ( ) ! = 0 )
2009-12-21 18:17:35 +01:00
checks . push_back ( new CheckNullpointer ( owner , vartok - > varId ( ) , vartok - > str ( ) ) ) ;
2009-12-20 19:44:32 +01:00
return vartok - > next ( ) ;
}
2010-01-03 13:30:20 +01:00
// Template pointer variable..
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% ::|< " ) )
{
const Token * vartok = & tok ;
while ( Token : : Match ( vartok , " %type% :: " ) )
vartok = vartok - > tokAt ( 2 ) ;
if ( Token : : Match ( vartok , " %type% < %type% " ) )
{
vartok = vartok - > tokAt ( 3 ) ;
while ( vartok & & ( vartok - > str ( ) = = " * " | | vartok - > isName ( ) ) )
vartok = vartok - > next ( ) ;
if ( Token : : Match ( vartok , " > * %var% ;|= " ) )
{
vartok = vartok - > tokAt ( 2 ) ;
checks . push_back ( new CheckNullpointer ( owner , vartok - > varId ( ) , vartok - > str ( ) ) ) ;
if ( Token : : simpleMatch ( vartok - > next ( ) , " = 0 ; " ) )
setnull ( checks , vartok - > varId ( ) ) ;
return vartok - > next ( ) ;
}
}
}
2009-12-23 19:59:46 +01:00
if ( Token : : Match ( & tok , " %var% ( " ) )
2009-12-23 19:51:32 +01:00
{
2010-01-14 20:02:38 +01:00
if ( tok . str ( ) = = " sizeof " )
return tok . next ( ) - > link ( ) ;
2009-12-23 19:51:32 +01:00
// parse usage..
std : : list < const Token * > var ;
parseFunctionCall ( tok , var , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
dereference ( foundError , checks , * it ) ;
}
2009-12-20 19:44:32 +01:00
if ( tok . varId ( ) ! = 0 )
2009-12-06 18:41:28 +01:00
{
2009-12-20 19:44:32 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}=] %var% = 0 ; " ) )
setnull ( checks , tok . varId ( ) ) ;
2009-12-31 20:00:20 +01:00
else if ( Token : : Match ( tok . tokAt ( - 2 ) , " [ ; { } = + - / ( , ] * % var % " ))
dereference ( foundError , checks , & tok ) ;
else if ( Token : : Match ( tok . tokAt ( - 2 ) , " return * %var% " ) )
2009-12-20 19:44:32 +01:00
dereference ( foundError , checks , & tok ) ;
2010-02-22 21:30:21 +01:00
else if ( ! Token : : simpleMatch ( tok . tokAt ( - 2 ) , " & ( " ) & & Token : : Match ( tok . next ( ) , " . %var% " ) )
2009-12-20 19:44:32 +01:00
dereference ( foundError , checks , & tok ) ;
2009-12-31 20:00:20 +01:00
else if ( Token : : Match ( tok . previous ( ) , " [ ; { } = + - / ( , ] % var % [ % any % ] " ))
dereference ( foundError , checks , & tok ) ;
else if ( Token : : Match ( tok . previous ( ) , " return %var% [ %any% ] " ) )
2009-12-21 19:09:13 +01:00
dereference ( foundError , checks , & tok ) ;
2010-01-23 09:15:30 +01:00
else if ( Token : : Match ( & tok , " %var% ( " ) )
dereference ( foundError , checks , & tok ) ;
2009-12-06 18:41:28 +01:00
else
2009-12-20 19:44:32 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
}
2009-12-20 19:44:32 +01:00
2009-12-30 17:42:41 +01:00
if ( Token : : simpleMatch ( & tok , " * 0 " ) )
{
2009-12-31 20:00:20 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}=+-/(,] " ) | |
2010-01-30 14:40:33 +01:00
Token : : Match ( tok . previous ( ) , " return|<< " ) )
2009-12-30 17:42:41 +01:00
{
CheckOther * checkOther = dynamic_cast < CheckOther * > ( owner ) ;
if ( checkOther )
{
checkOther - > nullPointerError ( & tok ) ;
foundError = true ;
}
}
}
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-25 19:45:21 +01:00
2009-12-25 20:50:23 +01:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks )
2009-12-25 19:45:21 +01:00
{
if ( Token : : Match ( & tok , " !| %var% ( " ) )
{
bool foundError = false ;
std : : list < const Token * > var ;
parseFunctionCall ( tok . str ( ) = = " ! " ? * tok . next ( ) : tok , var , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
dereference ( foundError , checks , * it ) ;
}
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2009-12-06 18:41:28 +01:00
} ;
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
class CheckUninitVar : public ExecutionPath
{
public :
// Startup constructor
2009-12-21 18:17:35 +01:00
CheckUninitVar ( Check * c )
2010-02-05 17:35:18 +01:00
: ExecutionPath ( c , 0 ) , pointer ( false ) , array ( false ) , alloc ( false ) , strncpy_ ( false )
2009-12-06 18:41:28 +01:00
{
}
private :
ExecutionPath * copy ( )
{
return new CheckUninitVar ( * this ) ;
}
2009-10-29 21:34:43 +01:00
2009-12-06 20:34:02 +01:00
/* no implementation */
void operator = ( const CheckUninitVar & ) ;
2009-12-21 18:17:35 +01:00
// internal constructor for creating extra checks
CheckUninitVar ( Check * c , unsigned int v , const std : : string & name , bool p , bool a )
2010-02-05 17:35:18 +01:00
: ExecutionPath ( c , v ) , varname ( name ) , pointer ( p ) , array ( a ) , alloc ( false ) , strncpy_ ( false )
2009-12-21 18:17:35 +01:00
{
}
const std : : string varname ;
2009-12-06 18:41:28 +01:00
const bool pointer ;
const bool array ;
2009-12-21 18:17:35 +01:00
bool alloc ;
2010-02-05 17:35:18 +01:00
bool strncpy_ ;
2009-12-21 18:17:35 +01:00
2009-12-26 09:30:02 +01:00
// p = malloc ..
2009-12-21 18:17:35 +01:00
static void alloc_pointer ( std : : list < ExecutionPath * > & checks , unsigned int varid )
2009-12-06 18:41:28 +01:00
{
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid )
c - > alloc = true ;
2009-10-29 21:34:43 +01:00
}
2009-12-06 18:41:28 +01:00
}
2009-10-29 21:34:43 +01:00
2009-12-26 09:30:02 +01:00
// *p = ..
static void init_pointer ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
std : : list < ExecutionPath * > : : iterator it = checks . begin ( ) ;
while ( it ! = checks . end ( ) )
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid )
2009-12-26 09:30:02 +01:00
{
2009-12-29 09:30:02 +01:00
if ( c - > alloc )
2009-12-26 09:30:02 +01:00
{
2009-12-29 09:30:02 +01:00
delete c ;
checks . erase ( it + + ) ;
continue ;
}
else
{
use_pointer ( foundError , checks , tok ) ;
2009-12-26 09:30:02 +01:00
}
}
+ + it ;
}
}
// free p;
2009-12-21 18:17:35 +01:00
static void dealloc_pointer ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
const unsigned int varid ( tok - > varId ( ) ) ;
2009-12-28 12:51:28 +01:00
if ( ! varid )
return ;
2009-12-21 18:17:35 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid )
2009-12-21 18:17:35 +01:00
{
2010-01-01 19:49:33 +01:00
if ( c - > pointer & & ! c - > alloc )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
if ( checkOther )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
foundError = true ;
checkOther - > uninitvarError ( tok , c - > varname ) ;
break ;
2009-12-21 18:17:35 +01:00
}
}
2009-12-29 09:30:02 +01:00
c - > alloc = false ;
2009-12-21 18:17:35 +01:00
}
}
}
2010-01-17 19:08:45 +01:00
/**
* Pointer assignment : p = x ;
* if p is a pointer and x is an array / pointer then bail out
* \ param checks all available checks
* \ param tok1 the " p " token
* \ param tok2 the " x " token
*/
static void pointer_assignment ( std : : list < ExecutionPath * > & checks , const Token * tok1 , const Token * tok2 )
{
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
if ( varid1 = = 0 )
return ;
const unsigned int varid2 ( tok2 - > varId ( ) ) ;
if ( varid2 = = 0 )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
// bail out if first variable is a pointer
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid1 & & c - > pointer )
{
bailOutVar ( checks , varid1 ) ;
break ;
}
}
// bail out if second variable is a array/pointer
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid2 & & ( c - > pointer | | c - > array ) )
{
bailOutVar ( checks , varid2 ) ;
break ;
}
}
}
2010-02-05 17:35:18 +01:00
/** Initialize an array with strncpy.. */
static void init_strncpy ( std : : list < ExecutionPath * > & checks , const Token * tok )
{
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varId = = varid )
{
c - > strncpy_ = true ;
}
}
}
2009-12-27 10:48:44 +01:00
/**
* use - called from the use * functions below .
* @ param foundError this is set to true if an error is found
* @ param checks all available checks
* @ param tok variable token
* @ param mode specific behaviour
*/
2009-12-21 18:17:35 +01:00
static void use ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok , const int mode )
{
const unsigned int varid ( tok - > varId ( ) ) ;
2009-12-23 15:01:23 +01:00
if ( varid = = 0 )
return ;
2009-12-21 18:17:35 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
2009-12-29 09:30:02 +01:00
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
2010-01-01 19:49:33 +01:00
if ( c & & c - > varId = = varid )
2009-12-21 18:17:35 +01:00
{
2009-12-29 09:30:02 +01:00
// mode 0 : the variable is used "directly"
// example: .. = var;
// it is ok to read the address of an uninitialized array.
// it is ok to read the address of an allocated pointer
if ( mode = = 0 & & ( c - > array | | ( c - > pointer & & c - > alloc ) ) )
continue ;
2009-12-27 10:48:44 +01:00
2009-12-29 09:30:02 +01:00
// mode 2 : bad usage of pointer. if it's not a pointer then the usage is ok.
// example: ptr->foo();
if ( mode = = 2 & & ! c - > pointer )
continue ;
2009-12-21 18:17:35 +01:00
2009-12-29 20:36:20 +01:00
// mode 3 : using dead pointer is invalid.
if ( mode = = 3 & & ( ! c - > pointer | | c - > alloc ) )
continue ;
2009-12-29 09:30:02 +01:00
CheckOther * checkOther = dynamic_cast < CheckOther * > ( c - > owner ) ;
if ( checkOther )
{
2010-02-05 17:35:18 +01:00
if ( c - > strncpy_ )
checkOther - > uninitstringError ( tok , c - > varname ) ;
else if ( c - > pointer & & c - > alloc )
2009-12-29 09:30:02 +01:00
checkOther - > uninitdataError ( tok , c - > varname ) ;
else
checkOther - > uninitvarError ( tok , c - > varname ) ;
foundError = true ;
break ;
2009-12-21 18:17:35 +01:00
}
}
}
}
2009-12-27 10:48:44 +01:00
/**
* Reading variable . Use this function in situations when it is
* invalid to read the data of the variable but not the address .
* @ param foundError this is set to true if an error is found
* @ param checks all available checks
* @ param tok variable token
*/
2009-12-21 18:17:35 +01:00
static void use ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
use ( foundError , checks , tok , 0 ) ;
}
2009-12-27 10:48:44 +01:00
/**
* Reading array elements . If the variable is not an array then the usage is ok .
* @ param foundError this is set to true if an error is found
* @ param checks all available checks
* @ param tok variable token
*/
2009-12-21 18:17:35 +01:00
static void use_array ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
use ( foundError , checks , tok , 1 ) ;
}
2009-12-27 10:48:44 +01:00
/**
* Bad pointer usage . If the variable is not a pointer then the usage is ok .
* @ param foundError this is set to true if an error is found
* @ param checks all available checks
* @ param tok variable token
*/
2009-12-21 18:17:35 +01:00
static void use_pointer ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
use ( foundError , checks , tok , 2 ) ;
}
2009-12-29 20:36:20 +01:00
/**
* Using variable . . if it ' s a dead pointer the usage is invalid .
* @ param foundError this is set to true if an error is found
* @ param checks all available checks
* @ param tok variable token
*/
static void use_dead_pointer ( bool & foundError , std : : list < ExecutionPath * > & checks , const Token * tok )
{
use ( foundError , checks , tok , 3 ) ;
}
2010-01-01 19:43:02 +01:00
void declare ( std : : list < ExecutionPath * > & checks , const Token * vartok , const Token & tok , const bool p , const bool a ) const
{
if ( vartok - > varId ( ) = = 0 )
return ;
2010-01-10 20:36:15 +01:00
bool isenum = false ;
2010-01-01 19:43:02 +01:00
if ( ! tok . isStandardType ( ) )
2010-01-10 20:36:15 +01:00
{
const std : : string pattern ( " enum " + tok . str ( ) ) ;
for ( const Token * tok2 = tok . previous ( ) ; tok2 ; tok2 = tok2 - > previous ( ) )
{
if ( tok2 - > str ( ) ! = " { " )
continue ;
if ( Token : : simpleMatch ( tok2 - > tokAt ( - 2 ) , pattern . c_str ( ) ) )
{
isenum = true ;
break ;
}
}
}
// Suppress warnings if variable in inner scope has same name as variable in outer scope
if ( ! tok . isStandardType ( ) & & ! isenum )
2010-01-01 19:43:02 +01:00
{
2010-01-01 19:49:33 +01:00
std : : set < unsigned int > dup ;
2010-01-01 19:43:02 +01:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
CheckUninitVar * c = dynamic_cast < CheckUninitVar * > ( * it ) ;
if ( c & & c - > varname = = vartok - > str ( ) & & c - > varId ! = vartok - > varId ( ) )
2010-01-01 19:49:33 +01:00
dup . insert ( c - > varId ) ;
2010-01-01 19:43:02 +01:00
}
2010-01-01 19:49:33 +01:00
if ( ! dup . empty ( ) )
{
for ( std : : set < unsigned int > : : const_iterator it = dup . begin ( ) ; it ! = dup . end ( ) ; + + it )
bailOutVar ( checks , * it ) ;
2010-01-01 19:43:02 +01:00
return ;
2010-01-01 19:49:33 +01:00
}
2010-01-01 19:43:02 +01:00
}
2010-01-10 20:36:15 +01:00
if ( a | | p | | tok . isStandardType ( ) | | isenum )
2010-01-01 19:43:02 +01:00
checks . push_back ( new CheckUninitVar ( owner , vartok - > varId ( ) , vartok - > str ( ) , p , a ) ) ;
}
2009-12-06 18:41:28 +01:00
const Token * parse ( const Token & tok , bool & foundError , std : : list < ExecutionPath * > & checks ) const
{
2009-12-21 18:17:35 +01:00
// Variable declaration..
2009-12-23 17:55:03 +01:00
if ( tok . str ( ) ! = " return " )
2009-10-29 21:34:43 +01:00
{
2010-01-10 20:36:15 +01:00
if ( Token : : Match ( & tok , " enum %type% { " ) )
return tok . tokAt ( 2 ) - > link ( ) ;
2009-12-23 17:55:03 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% *| %var% ; " ) )
{
const Token * vartok = tok . next ( ) ;
const bool p ( vartok - > str ( ) = = " * " ) ;
if ( p )
vartok = vartok - > next ( ) ;
2010-01-01 19:43:02 +01:00
declare ( checks , vartok , tok , p , false ) ;
2009-12-23 17:55:03 +01:00
return vartok - > next ( ) ;
}
2009-12-21 18:17:35 +01:00
2009-12-23 17:55:03 +01:00
// Variable declaration for array..
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% %var% [ %num% ] ; " ) )
{
const Token * vartok = tok . next ( ) ;
2010-01-01 19:43:02 +01:00
declare ( checks , vartok , tok , false , true ) ;
2009-12-23 17:55:03 +01:00
return vartok - > next ( ) - > link ( ) - > next ( ) ;
}
2010-01-03 13:30:20 +01:00
// Template pointer variable..
if ( Token : : Match ( tok . previous ( ) , " [;{}] %type% ::|< " ) )
{
const Token * vartok = & tok ;
while ( Token : : Match ( vartok , " %type% :: " ) )
vartok = vartok - > tokAt ( 2 ) ;
if ( Token : : Match ( vartok , " %type% < %type% " ) )
{
vartok = vartok - > tokAt ( 3 ) ;
while ( vartok & & ( vartok - > str ( ) = = " * " | | vartok - > isName ( ) ) )
vartok = vartok - > next ( ) ;
if ( Token : : Match ( vartok , " > * %var% ; " ) )
{
declare ( checks , vartok - > tokAt ( 2 ) , tok , true , false ) ;
return vartok - > tokAt ( 2 ) ;
}
}
}
2009-12-21 18:17:35 +01:00
}
if ( tok . varId ( ) )
{
2010-01-09 22:26:05 +01:00
// Used..
2010-01-11 22:28:07 +01:00
if ( Token : : Match ( tok . previous ( ) , " [[(,+-*/] %var% []),+-*/] " ) )
2010-01-09 22:26:05 +01:00
{
use ( foundError , checks , & tok ) ;
return & tok ;
}
2010-01-10 09:09:37 +01:00
if ( Token : : Match ( tok . previous ( ) , " ++|-- " ) | | Token : : Match ( tok . next ( ) , " ++|-- " ) )
{
use ( foundError , checks , & tok ) ;
return & tok ;
}
2009-12-30 20:15:44 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %var% = " ) )
{
// using same variable rhs?
for ( const Token * tok2 = tok . tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( Token : : Match ( tok2 , " ;|)|= " ) )
break ;
if ( Token : : Match ( tok2 , " %var% ( " ) )
break ;
2009-12-30 21:42:15 +01:00
if ( tok2 - > varId ( ) & &
2010-01-03 08:03:28 +01:00
! Token : : Match ( tok2 - > previous ( ) , " &|:: " ) & &
2009-12-30 21:42:15 +01:00
! Token : : simpleMatch ( tok2 - > next ( ) , " = " ) )
2009-12-30 20:15:44 +01:00
use ( foundError , checks , tok2 ) ;
}
2010-01-17 19:08:45 +01:00
// pointer aliasing?
if ( Token : : Match ( tok . tokAt ( 2 ) , " %var% ; " ) )
{
pointer_assignment ( checks , & tok , tok . tokAt ( 2 ) ) ;
}
2009-12-30 20:15:44 +01:00
}
2010-01-23 07:57:57 +01:00
if ( Token : : simpleMatch ( tok . next ( ) , " ( " ) )
{
use_pointer ( foundError , checks , & tok ) ;
}
2009-12-21 18:17:35 +01:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [;{}] * " ) )
2009-12-06 18:41:28 +01:00
{
2009-12-26 09:30:02 +01:00
if ( Token : : simpleMatch ( tok . next ( ) , " = " ) )
init_pointer ( foundError , checks , & tok ) ;
else
use_pointer ( foundError , checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-15 20:26:07 +01:00
2010-01-03 18:49:13 +01:00
// += etc
if ( Token : : Match ( tok . previous ( ) , " [;{}] " ) | | Token : : Match ( tok . tokAt ( - 2 ) , " [;{}] * " ) )
{
// goto the equal..
const Token * eq = tok . next ( ) ;
if ( eq & & eq - > str ( ) = = " [ " & & eq - > link ( ) & & eq - > link ( ) - > next ( ) )
eq = eq - > link ( ) - > next ( ) ;
// is it X=
if ( Token : : Match ( eq , " +=|-=|*=|/=|&=|^= " ) | | eq - > str ( ) = = " |= " )
{
if ( tok . previous ( ) - > str ( ) = = " * " )
use_pointer ( foundError , checks , & tok ) ;
else if ( tok . next ( ) - > str ( ) = = " [ " )
use_array ( foundError , checks , & tok ) ;
else
use ( foundError , checks , & tok ) ;
}
}
2009-12-22 21:00:52 +01:00
if ( Token : : Match ( tok . next ( ) , " = malloc|kmalloc " ) | | Token : : simpleMatch ( tok . next ( ) , " = new char [ " ) )
2009-11-02 16:28:15 +01:00
{
2009-12-21 18:17:35 +01:00
alloc_pointer ( checks , tok . varId ( ) ) ;
2009-12-26 09:30:02 +01:00
if ( tok . tokAt ( 3 ) - > str ( ) = = " ( " )
return tok . tokAt ( 3 ) - > link ( ) ;
2009-12-21 18:17:35 +01:00
}
else if ( Token : : simpleMatch ( tok . previous ( ) , " >> " ) | | Token : : simpleMatch ( tok . next ( ) , " = " ) )
{
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-02 16:28:15 +01:00
}
2009-11-03 21:02:16 +01:00
2009-12-06 18:41:28 +01:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) )
2009-11-03 21:02:16 +01:00
{
2009-12-06 18:41:28 +01:00
const Token * tok2 = tok . next ( ) - > link ( ) ;
2009-11-03 21:02:16 +01:00
if ( Token : : simpleMatch ( tok2 ? tok2 - > next ( ) : 0 , " = " ) )
{
2010-01-09 22:26:05 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-03 21:02:16 +01:00
}
}
2009-11-15 20:01:57 +01:00
2009-12-06 18:41:28 +01:00
if ( Token : : simpleMatch ( tok . previous ( ) , " delete " ) | |
Token : : simpleMatch ( tok . tokAt ( - 3 ) , " delete [ ] " ) )
2009-11-15 20:01:57 +01:00
{
2009-12-21 18:17:35 +01:00
dealloc_pointer ( foundError , checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
2009-11-15 20:01:57 +01:00
}
2009-10-29 21:34:43 +01:00
}
2010-01-11 22:28:07 +01:00
if ( Token : : Match ( & tok , " %var% ( " ) & & uvarFunctions . find ( tok . str ( ) ) = = uvarFunctions . end ( ) )
2009-10-30 14:06:40 +01:00
{
2009-12-30 11:32:46 +01:00
if ( Token : : simpleMatch ( & tok , " sizeof ( " ) )
return tok . next ( ) - > link ( ) ;
2009-12-27 18:00:43 +01:00
// deallocate pointer
if ( Token : : Match ( & tok , " free|kfree|fclose ( %var% ) " ) )
{
dealloc_pointer ( foundError , checks , tok . tokAt ( 2 ) ) ;
return tok . tokAt ( 3 ) ;
}
2009-12-23 19:51:32 +01:00
// parse usage..
2009-11-03 17:03:53 +01:00
{
2009-12-23 19:51:32 +01:00
std : : list < const Token * > var ;
parseFunctionCall ( tok , var , 1 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
use_array ( foundError , checks , * it ) ;
2009-12-06 18:41:28 +01:00
}
2009-12-21 18:17:35 +01:00
// strncpy doesn't 0-terminate first parameter
2010-02-05 17:35:18 +01:00
if ( Token : : Match ( & tok , " strncpy ( %var% , " ) )
{
init_strncpy ( checks , tok . tokAt ( 2 ) ) ;
2009-12-21 18:17:35 +01:00
return tok . next ( ) - > link ( ) ;
2010-02-05 17:35:18 +01:00
}
2009-12-21 18:17:35 +01:00
2009-12-06 18:41:28 +01:00
if ( Token : : Match ( & tok , " asm ( ) " ) )
{
ExecutionPath : : bailOut ( checks ) ;
return & tok ;
2009-11-03 17:03:53 +01:00
}
2009-10-31 16:36:56 +01:00
2009-10-30 14:06:40 +01:00
// is the variable passed as a parameter to some function?
unsigned int parlevel = 0 ;
2010-01-03 13:30:20 +01:00
std : : set < unsigned int > bailouts ;
2009-12-06 18:41:28 +01:00
for ( const Token * tok2 = tok . next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-10-30 14:06:40 +01:00
{
2009-11-03 17:03:53 +01:00
if ( tok2 - > str ( ) = = " ( " )
2009-11-15 12:42:04 +01:00
+ + parlevel ;
else if ( tok2 - > str ( ) = = " ) " )
{
if ( parlevel < = 1 )
break ;
- - parlevel ;
}
2009-12-31 09:10:20 +01:00
else if ( Token : : simpleMatch ( tok2 , " sizeof ( " ) )
{
2010-01-02 18:16:44 +01:00
tok2 = tok2 - > next ( ) - > link ( ) ;
2009-12-31 09:10:20 +01:00
if ( ! tok2 )
break ;
}
2009-12-21 18:17:35 +01:00
else if ( tok2 - > varId ( ) )
2009-11-15 12:42:04 +01:00
{
2010-01-03 13:30:20 +01:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [(,] * " ) | | Token : : Match ( tok2 - > next ( ) , " . %var% " ) )
2009-12-29 20:36:20 +01:00
use_dead_pointer ( foundError , checks , tok2 ) ;
2009-11-15 12:42:04 +01:00
// it is possible that the variable is initialized here
2010-01-03 13:30:20 +01:00
bailouts . insert ( tok2 - > varId ( ) ) ;
2009-11-15 12:42:04 +01:00
}
}
2010-01-03 13:30:20 +01:00
for ( std : : set < unsigned int > : : const_iterator it = bailouts . begin ( ) ; it ! = bailouts . end ( ) ; + + it )
ExecutionPath : : bailOutVar ( checks , * it ) ;
2009-11-15 12:42:04 +01:00
}
// function call via function pointer
2009-12-06 18:41:28 +01:00
if ( Token : : Match ( & tok , " ( * %var% ) ( " ) )
2009-11-15 12:42:04 +01:00
{
// is the variable passed as a parameter to some function?
unsigned int parlevel = 0 ;
2009-12-06 18:41:28 +01:00
for ( const Token * tok2 = tok . link ( ) - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-11-15 12:42:04 +01:00
{
if ( tok2 - > str ( ) = = " ( " )
2009-10-30 14:06:40 +01:00
+ + parlevel ;
2009-11-03 17:03:53 +01:00
else if ( tok2 - > str ( ) = = " ) " )
2009-10-30 14:06:40 +01:00
{
if ( parlevel < = 1 )
break ;
- - parlevel ;
}
2009-12-21 18:17:35 +01:00
else if ( tok2 - > varId ( ) )
2009-10-30 14:06:40 +01:00
{
// it is possible that the variable is initialized here
2009-12-21 18:17:35 +01:00
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
2009-10-30 14:06:40 +01:00
}
}
}
2009-12-06 18:41:28 +01:00
if ( tok . str ( ) = = " return " )
2009-11-06 16:02:13 +01:00
{
2009-12-21 18:17:35 +01:00
// Todo: if (!array && ..
if ( Token : : Match ( tok . next ( ) , " %var% ; " ) )
2009-11-06 16:02:13 +01:00
{
2009-12-21 18:17:35 +01:00
use ( foundError , checks , tok . next ( ) ) ;
2009-11-06 16:02:13 +01:00
}
}
2009-12-21 18:17:35 +01:00
if ( tok . varId ( ) )
2009-10-30 14:31:37 +01:00
{
2009-12-06 18:41:28 +01:00
if ( Token : : simpleMatch ( tok . previous ( ) , " = " ) )
2009-11-03 17:03:53 +01:00
{
2009-12-15 19:50:48 +01:00
if ( Token : : Match ( tok . tokAt ( - 3 ) , " & %var% = " ) )
{
2009-12-21 18:17:35 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-15 19:50:48 +01:00
return & tok ;
}
2009-12-06 18:41:28 +01:00
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " . %var% = " ) )
2009-11-03 17:03:53 +01:00
{
2009-12-06 18:41:28 +01:00
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " [;{}] %var% = " ) )
{
2009-12-21 18:17:35 +01:00
use ( foundError , checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-05 21:07:04 +01:00
2009-12-06 18:41:28 +01:00
const unsigned int varid2 = tok . tokAt ( - 2 ) - > varId ( ) ;
2009-11-05 21:07:04 +01:00
if ( varid2 )
{
2009-12-21 18:17:35 +01:00
/*
const Token * tok2 = Token : : findmatch ( owner - > _tokenizer - > tokens ( ) , " %varid% " , varid2 ) ;
2009-11-05 21:07:04 +01:00
if ( tok2 & & ! Token : : simpleMatch ( tok2 - > previous ( ) , " * " ) )
2009-12-21 18:17:35 +01:00
*/
2009-12-06 18:41:28 +01:00
{
2009-12-21 18:17:35 +01:00
use ( foundError , checks , & tok ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-11-05 21:07:04 +01:00
}
2009-11-03 17:03:53 +01:00
}
}
2009-11-02 19:58:49 +01:00
2009-12-21 18:17:35 +01:00
if ( Token : : simpleMatch ( tok . next ( ) , " . " ) )
2009-12-06 18:41:28 +01:00
{
2009-12-27 17:35:18 +01:00
if ( ! Token : : Match ( tok . previous ( ) , " [;{}] %var% . %var% = " ) )
use_pointer ( foundError , checks , & tok ) ;
2010-01-23 21:25:17 +01:00
else
bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-21 18:17:35 +01:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) )
2009-12-06 18:41:28 +01:00
{
2009-12-21 18:17:35 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2009-12-06 18:41:28 +01:00
return & tok ;
}
2009-12-27 17:20:34 +01:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [,(=] * " ) )
{
2009-12-30 20:37:11 +01:00
use_pointer ( foundError , checks , & tok ) ;
2009-12-27 17:20:34 +01:00
return & tok ;
}
2010-01-11 19:25:01 +01:00
if ( Token : : simpleMatch ( tok . previous ( ) , " & " ) )
{
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
}
2009-12-06 18:41:28 +01:00
}
return & tok ;
}
2009-12-25 19:45:21 +01:00
2009-12-25 20:50:23 +01:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks )
2009-12-25 19:45:21 +01:00
{
bool foundError = false ;
if ( tok . varId ( ) & & Token : : Match ( & tok , " %var% <|<=|==|!=|)|[ " ) )
2009-12-27 10:48:44 +01:00
use ( foundError , checks , & tok ) ;
2009-12-25 19:45:21 +01:00
else if ( Token : : Match ( & tok , " !| %var% ( " ) )
{
std : : list < const Token * > var ;
parseFunctionCall ( tok . str ( ) = = " ! " ? * tok . next ( ) : tok , var , 1 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
use_array ( foundError , checks , * it ) ;
}
2009-12-30 20:37:11 +01:00
else if ( Token : : Match ( & tok , " ! %var% ) " ) )
{
use ( foundError , checks , & tok ) ;
return false ;
}
2009-12-25 19:45:21 +01:00
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2010-01-11 22:28:07 +01:00
public :
static std : : set < std : : string > uvarFunctions ;
static void analyseFunctions ( const Token * const tokens , std : : set < std : : string > & func )
{
for ( const Token * tok = tokens ; tok ; tok = tok - > next ( ) )
{
if ( tok - > str ( ) = = " { " )
{
tok = tok - > link ( ) ;
continue ;
}
if ( tok - > str ( ) ! = " :: " & & Token : : Match ( tok - > next ( ) , " %var% ( %type% " ) )
{
if ( ! Token : : simpleMatch ( tok - > tokAt ( 2 ) - > link ( ) , " ) { " ) )
continue ;
const Token * tok2 = tok - > tokAt ( 3 ) ;
while ( tok2 & & tok2 - > str ( ) ! = " ) " )
{
if ( tok2 - > str ( ) = = " , " )
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " %type% %var% ,|) " ) & & tok2 - > isStandardType ( ) )
{
tok2 = tok2 - > tokAt ( 2 ) ;
continue ;
}
if ( Token : : Match ( tok2 , " const %type% %var% ,|) " ) & & tok2 - > next ( ) - > isStandardType ( ) )
{
tok2 = tok2 - > tokAt ( 2 ) ;
continue ;
}
break ;
}
// found simple function..
if ( tok2 - > link ( ) = = tok - > tokAt ( 2 ) )
func . insert ( tok - > next ( ) - > str ( ) ) ;
}
}
}
2009-12-06 18:41:28 +01:00
} ;
2010-01-11 22:28:07 +01:00
std : : set < std : : string > CheckUninitVar : : uvarFunctions ;
void CheckOther : : analyseFunctions ( const Token * const tokens , std : : set < std : : string > & func )
{
CheckUninitVar : : analyseFunctions ( tokens , func ) ;
}
2009-12-06 18:41:28 +01:00
2009-10-29 21:34:43 +01:00
2009-12-06 18:41:28 +01:00
void CheckOther : : executionPaths ( )
2009-10-29 21:34:43 +01:00
{
2009-12-25 20:12:06 +01:00
// Check for null pointer errors..
2009-10-29 21:34:43 +01:00
{
2009-12-25 20:12:06 +01:00
CheckNullpointer c ( this ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
}
2009-12-21 18:17:35 +01:00
2009-12-25 20:12:06 +01:00
// check if variable is accessed uninitialized..
{
2010-01-12 22:33:47 +01:00
// no writing if multiple threads are used (TODO: thread safe analysis?)
if ( _settings - > _jobs = = 1 )
CheckUninitVar : : analyseFunctions ( _tokenizer - > tokens ( ) , CheckUninitVar : : uvarFunctions ) ;
2009-12-25 20:12:06 +01:00
CheckUninitVar c ( this ) ;
checkExecutionPaths ( _tokenizer - > tokens ( ) , & c ) ;
2009-10-29 21:34:43 +01:00
}
}
2009-07-05 22:16:43 +02:00
void CheckOther : : checkZeroDivision ( )
2009-03-28 07:49:47 +01:00
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-09-01 21:06:46 +02:00
2009-09-01 16:00:26 +02:00
if ( Token : : Match ( tok , " / %num% " ) & &
2009-09-01 21:06:46 +02:00
MathLib : : isInt ( tok - > next ( ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) = = 0L )
2009-08-23 05:34:19 +02:00
{
2009-03-29 18:47:05 +02:00
zerodivError ( tok ) ;
2009-08-23 05:34:19 +02:00
}
2009-09-01 21:06:46 +02:00
else if ( Token : : Match ( tok , " div|ldiv|lldiv|imaxdiv ( %num% , %num% ) " ) & &
MathLib : : isInt ( tok - > tokAt ( 4 ) - > str ( ) ) & &
MathLib : : toLongNumber ( tok - > tokAt ( 4 ) - > str ( ) ) = = 0L )
2009-08-23 05:34:19 +02:00
{
zerodivError ( tok ) ;
}
2009-03-28 07:49:47 +01:00
}
}
2009-07-25 00:36:15 +02:00
void CheckOther : : postIncrement ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-07-25 19:36:57 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) )
2009-07-25 00:36:15 +02:00
{
2009-07-25 19:36:57 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) ;
if ( tok2 )
tok2 = tok2 - > tokAt ( - 3 ) ;
2009-07-25 00:36:15 +02:00
if ( Token : : Match ( tok2 , " ; %var% ++|-- ) " ) )
{
2009-07-26 11:46:00 +02:00
if ( tok2 - > next ( ) - > varId ( ) = = 0 )
continue ;
2009-07-25 00:36:15 +02:00
// Take a look at the variable declaration
const Token * decltok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok2 - > tokAt ( 1 ) - > varId ( ) ) ;
const std : : string classDef = std : : string ( " class " ) + std : : string ( decltok - > previous ( ) - > strAt ( 0 ) ) ;
// Is the variable an iterator?
if ( decltok & & Token : : Match ( decltok - > previous ( ) , " iterator|const_iterator " ) )
postIncrementError ( tok2 , tok2 - > strAt ( 1 ) , ( std : : string ( " ++ " ) = = tok2 - > strAt ( 2 ) ) ) ;
// Is the variable a class?
2009-07-25 01:23:30 +02:00
else if ( Token : : findmatch ( _tokenizer - > tokens ( ) , classDef . c_str ( ) ) )
2009-07-25 00:36:15 +02:00
postIncrementError ( tok2 , tok2 - > strAt ( 1 ) , ( std : : string ( " ++ " ) = = tok2 - > strAt ( 2 ) ) ) ;
}
}
}
}
2009-03-28 07:49:47 +01:00
2009-03-21 17:58:13 +01:00
void CheckOther : : cstyleCastError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " cstyleCast " , " C-style pointer casting " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : redundantIfDelete0Error ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " redundantIfDelete0 " , " Redundant condition. It is safe to deallocate a NULL pointer " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : redundantIfRemoveError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " redundantIfRemove " , " Redundant condition. The remove function in the STL will not do anything if element doesn't exist " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : dangerousUsageStrtolError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " dangerousUsageStrtol " , " Invalid radix in call to strtol or strtoul. Must be 0 or 2-36 " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : sprintfOverlappingDataError ( const Token * tok , const std : : string & varname )
{
2009-12-21 21:05:55 +01:00
reportError ( tok , Severity : : error , " sprintfOverlappingData " , " Undefined behaviour: " + varname + " is used wrong in call to sprintf or snprintf. Quote: If copying takes place between objects that overlap as a result of a call to sprintf() or snprintf(), the results are undefined. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : udivError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " udivError " , " Unsigned division. The result will be wrong. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : udivWarning ( const Token * tok )
{
2009-09-15 20:46:47 +02:00
reportError ( tok , Severity : : possibleStyle , " udivWarning " , " Division with signed and unsigned operators " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : unusedStructMemberError ( const Token * tok , const std : : string & structname , const std : : string & varname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " unusedStructMember " , " struct or union member ' " + structname + " :: " + varname + " ' is never used " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : passedByValueError ( const Token * tok , const std : : string & parname )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " passedByValue " , " Function parameter ' " + parname + " ' is passed by value. It could be passed by reference instead. " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : constStatementError ( const Token * tok , const std : : string & type )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " constStatement " , " Redundant code: Found a statement that begins with " + type + " constant " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : charArrayIndexError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " charArrayIndex " , " Warning - using char variable as array index " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : charBitOpError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " charBitOp " , " Warning - using char variable in bit operation " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : variableScopeError ( const Token * tok , const std : : string & varname )
{
2010-01-12 19:34:33 +01:00
reportError ( tok , Severity : : style , " variableScope " , " The scope of the variable " + varname + " can be reduced " ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : conditionAlwaysTrueFalse ( const Token * tok , const std : : string & truefalse )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : style , " conditionAlwaysTrueFalse " , " Condition is always " + truefalse ) ;
2009-03-21 17:58:13 +01:00
}
void CheckOther : : strPlusChar ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " strPlusChar " , " Unusual pointer arithmetic " ) ;
2009-03-21 17:58:13 +01:00
}
2009-12-30 17:42:41 +01:00
void CheckOther : : nullPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " nullPointer " , " Null pointer dereference " ) ;
}
2009-08-11 17:18:01 +02:00
void CheckOther : : nullPointerError ( const Token * tok , const std : : string & varname )
2009-03-27 17:19:34 +01:00
{
2009-08-11 17:18:01 +02:00
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference: " + varname ) ;
2009-03-27 17:19:34 +01:00
}
2009-03-28 07:49:47 +01:00
2009-08-21 12:42:40 +02:00
void CheckOther : : nullPointerError ( const Token * tok , const std : : string & varname , const int line )
{
2009-08-21 14:50:13 +02:00
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference: " + varname + " - otherwise it is redundant to check if " + varname + " is null at line " + MathLib : : toString < long > ( line ) ) ;
2009-08-21 12:42:40 +02:00
}
2010-02-05 17:35:18 +01:00
void CheckOther : : uninitstringError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitstring " , " Dangerous usage of ' " + varname + " ' (strncpy doesn't always 0-terminate it) " ) ;
}
2009-11-07 09:10:15 +01:00
void CheckOther : : uninitdataError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitdata " , " Data is allocated but not initialized: " + varname ) ;
}
2009-10-29 21:34:43 +01:00
void CheckOther : : uninitvarError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitvar " , " Uninitialized variable: " + varname ) ;
}
2009-03-29 18:47:05 +02:00
void CheckOther : : zerodivError ( const Token * tok )
2009-03-28 07:49:47 +01:00
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " zerodiv " , " Division by zero " ) ;
2009-03-28 07:49:47 +01:00
}
2009-07-25 00:36:15 +02:00
void CheckOther : : postIncrementError ( const Token * tok , const std : : string & var_name , const bool isIncrement )
{
2009-07-25 01:23:30 +02:00
std : : string type = ( isIncrement ? " Incrementing " : " Decrementing " ) ;
reportError ( tok , Severity : : possibleStyle , " postIncrementDecrement " , ( " Pre- " + type + " variable ' " + var_name + " ' is preferred to Post- " + type ) ) ;
2009-07-25 00:36:15 +02:00
}