2010-10-31 12:31:11 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2013-01-01 17:29:08 +01:00
* Copyright ( C ) 2007 - 2013 Daniel Marjamäki and Cppcheck team .
2010-10-31 12:31:11 +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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checkuninitvar.h"
# include "mathlib.h"
# include "executionpath.h"
# include "checknullpointer.h" // CheckNullPointer::parseFunctionCall
2011-12-13 21:57:27 +01:00
# include "symboldatabase.h"
2010-10-31 12:31:11 +01:00
# include <algorithm>
2012-12-24 19:11:13 +01:00
# include <map>
2013-01-24 19:41:15 +01:00
# include <cassert>
2010-10-31 12:31:11 +01:00
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
2011-10-13 20:53:06 +02:00
namespace {
2011-11-30 18:57:52 +01:00
CheckUninitVar instance ;
2010-10-31 12:31:11 +01:00
}
//---------------------------------------------------------------------------
2012-07-17 07:03:40 +02:00
// Skip [ .. ]
static const Token * skipBrackets ( const Token * tok )
{
while ( tok & & tok - > str ( ) = = " [ " )
tok = tok - > link ( ) - > next ( ) ;
return tok ;
}
2010-10-31 12:31:11 +01:00
/// @addtogroup Checks
/// @{
/**
* @ brief % Check that uninitialized variables aren ' t used ( using ExecutionPath )
* */
2011-10-13 20:53:06 +02:00
class UninitVar : public ExecutionPath {
2010-10-31 12:31:11 +01:00
public :
/** Startup constructor */
2012-06-22 19:57:07 +02:00
explicit UninitVar ( Check * c , const SymbolDatabase * db , bool isc )
: ExecutionPath ( c , 0 ) , symbolDatabase ( db ) , isC ( isc ) , var ( 0 ) , alloc ( false ) , strncpy_ ( false ) , memset_nonzero ( false ) {
2010-10-31 12:31:11 +01:00
}
private :
/** Create a copy of this check */
2011-10-13 20:53:06 +02:00
ExecutionPath * copy ( ) {
2010-10-31 12:31:11 +01:00
return new UninitVar ( * this ) ;
}
/** no implementation => compiler error if used */
void operator = ( const UninitVar & ) ;
/** internal constructor for creating extra checks */
2012-06-22 19:57:07 +02:00
UninitVar ( Check * c , const Variable * v , const SymbolDatabase * db , bool isc )
: ExecutionPath ( c , v - > varId ( ) ) , symbolDatabase ( db ) , isC ( isc ) , var ( v ) , alloc ( false ) , strncpy_ ( false ) , memset_nonzero ( false ) {
2010-10-31 12:31:11 +01:00
}
/** is other execution path equal? */
2011-10-13 20:53:06 +02:00
bool is_equal ( const ExecutionPath * e ) const {
2010-10-31 12:31:11 +01:00
const UninitVar * c = static_cast < const UninitVar * > ( e ) ;
2012-05-25 13:40:18 +02:00
return ( var = = c - > var & & alloc = = c - > alloc & & strncpy_ = = c - > strncpy_ & & memset_nonzero = = c - > memset_nonzero ) ;
2010-10-31 12:31:11 +01:00
}
2012-05-25 13:40:18 +02:00
/** pointer to symbol database */
const SymbolDatabase * symbolDatabase ;
2010-10-31 12:31:11 +01:00
2012-06-22 19:57:07 +02:00
const bool isC ;
2012-05-25 13:40:18 +02:00
/** variable for this check */
const Variable * var ;
2010-10-31 12:31:11 +01:00
/** is this variable allocated? */
bool alloc ;
/** is this variable initialized with strncpy (not always zero-terminated) */
bool strncpy_ ;
2011-09-05 19:42:48 +02:00
/** is this variable initialized but not zero-terminated (memset) */
bool memset_nonzero ;
2010-10-31 12:31:11 +01:00
/** allocating pointer. For example : p = malloc(10); */
2011-10-13 20:53:06 +02:00
static void alloc_pointer ( std : : list < ExecutionPath * > & checks , unsigned int varid ) {
2011-01-01 18:24:27 +01:00
// loop through the checks and perform a allocation if the
// variable id matches
2010-10-31 12:31:11 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2012-05-14 18:34:39 +02:00
if ( c & & c - > varId = = varid ) {
2012-05-25 13:40:18 +02:00
if ( c - > var - > isPointer ( ) & & ! c - > var - > isArray ( ) )
2012-05-14 18:34:39 +02:00
c - > alloc = true ;
else
bailOutVar ( checks , varid ) ;
break ;
}
2010-10-31 12:31:11 +01:00
}
}
/** Initializing a pointer value. For example: *p = 0; */
2011-10-13 20:53:06 +02:00
static void init_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 12:31:11 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
2011-01-01 18:24:27 +01:00
// loop through the checks and perform a initialization if the
// variable id matches
2010-10-31 12:31:11 +01:00
std : : list < ExecutionPath * > : : iterator it = checks . begin ( ) ;
2011-10-13 20:53:06 +02:00
while ( it ! = checks . end ( ) ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid ) {
2012-05-25 13:40:18 +02:00
if ( c - > alloc | | c - > var - > isArray ( ) ) {
2010-10-31 12:31:11 +01:00
delete c ;
checks . erase ( it + + ) ;
continue ;
2011-10-13 20:53:06 +02:00
} else {
2010-10-31 12:31:11 +01:00
use_pointer ( checks , tok ) ;
}
}
+ + it ;
}
}
/** Deallocate a pointer. For example: free(p); */
2011-10-13 20:53:06 +02:00
static void dealloc_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 12:31:11 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
2011-01-01 18:24:27 +01:00
// loop through the checks and perform a deallocation if the
// variable id matches
2010-10-31 12:31:11 +01:00
std : : list < ExecutionPath * > : : const_iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid ) {
2011-01-01 18:24:27 +01:00
// unallocated pointer variable => error
2012-05-25 13:40:18 +02:00
if ( c - > var - > isPointer ( ) & & ! c - > var - > isArray ( ) & & ! c - > alloc ) {
2010-10-31 12:31:11 +01:00
CheckUninitVar * checkUninitVar = dynamic_cast < CheckUninitVar * > ( c - > owner ) ;
2011-10-13 20:53:06 +02:00
if ( checkUninitVar ) {
2012-05-25 13:40:18 +02:00
checkUninitVar - > uninitvarError ( tok , c - > var - > name ( ) ) ;
2010-10-31 12:31:11 +01:00
break ;
}
}
c - > alloc = false ;
}
}
}
/**
* 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
*/
2011-10-13 20:53:06 +02:00
static void pointer_assignment ( std : : list < ExecutionPath * > & checks , const Token * tok1 , const Token * tok2 ) {
2011-01-01 18:24:27 +01:00
// Variable id for "left hand side" variable
2010-10-31 12:31:11 +01:00
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
if ( varid1 = = 0 )
return ;
2011-01-01 18:24:27 +01:00
// Variable id for "right hand side" variable
2010-10-31 12:31:11 +01:00
const unsigned int varid2 ( tok2 - > varId ( ) ) ;
if ( varid2 = = 0 )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
// bail out if first variable is a pointer
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2012-05-25 13:40:18 +02:00
if ( c & & c - > varId = = varid1 & & c - > var - > isPointer ( ) & & ! c - > var - > isArray ( ) ) {
2010-10-31 12:31:11 +01:00
bailOutVar ( checks , varid1 ) ;
break ;
}
}
// bail out if second variable is a array/pointer
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2012-05-25 13:40:18 +02:00
if ( c & & c - > varId = = varid2 & & ( c - > var - > isPointer ( ) | | c - > var - > isArray ( ) ) ) {
2010-10-31 12:31:11 +01:00
bailOutVar ( checks , varid2 ) ;
break ;
}
}
}
/** Initialize an array with strncpy. */
2011-10-13 20:53:06 +02:00
static void init_strncpy ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 12:31:11 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid ) {
2010-10-31 12:31:11 +01:00
c - > strncpy_ = true ;
}
}
}
2011-09-05 19:42:48 +02:00
/** Initialize an array with memset (not zero). */
2011-10-13 20:53:06 +02:00
static void init_memset_nonzero ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2011-09-05 19:42:48 +02:00
const unsigned int varid ( tok - > varId ( ) ) ;
if ( ! varid )
return ;
std : : list < ExecutionPath * > : : const_iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2011-09-05 19:42:48 +02:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid ) {
2011-09-05 19:42:48 +02:00
c - > memset_nonzero = true ;
}
}
}
2010-10-31 12:31:11 +01:00
/**
* use - called from the use * functions below .
* @ param checks all available checks
* @ param tok variable token
* @ param mode specific behaviour
* @ return if error is found , true is returned
*/
2011-10-13 20:53:06 +02:00
static bool use ( std : : list < ExecutionPath * > & checks , const Token * tok , const int mode ) {
2010-10-31 12:31:11 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
if ( varid = = 0 )
return false ;
std : : list < ExecutionPath * > : : const_iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 12:31:11 +01:00
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid ) {
2010-10-31 12:31:11 +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
2012-05-25 13:40:18 +02:00
if ( mode = = 0 & & ( c - > var - > isArray ( ) | | ( c - > var - > isPointer ( ) & & c - > alloc ) ) )
2010-10-31 12:31:11 +01:00
continue ;
2011-10-29 19:11:42 +02:00
// mode 2 : reading array data with mem.. function. It's ok if the
2012-11-03 21:21:19 +01:00
// array is not null-terminated
2011-10-29 19:11:42 +02:00
if ( mode = = 2 & & c - > strncpy_ )
continue ;
// mode 3 : bad usage of pointer. if it's not a pointer then the usage is ok.
2010-10-31 12:31:11 +01:00
// example: ptr->foo();
2012-05-25 13:40:18 +02:00
if ( mode = = 3 & & ( ! c - > var - > isPointer ( ) | | c - > var - > isArray ( ) ) )
2010-10-31 12:31:11 +01:00
continue ;
2011-10-29 19:11:42 +02:00
// mode 4 : using dead pointer is invalid.
2012-05-25 13:40:18 +02:00
if ( mode = = 4 & & ( ! c - > var - > isPointer ( ) | | c - > var - > isArray ( ) | | c - > alloc ) )
2010-10-31 12:31:11 +01:00
continue ;
2011-10-29 19:11:42 +02:00
// mode 5 : reading uninitialized array or pointer is invalid.
2012-05-25 13:40:18 +02:00
if ( mode = = 5 & & ( ! c - > var - > isArray ( ) & & ! c - > var - > isPointer ( ) ) )
2010-10-31 12:31:11 +01:00
continue ;
CheckUninitVar * checkUninitVar = dynamic_cast < CheckUninitVar * > ( c - > owner ) ;
2011-10-13 20:53:06 +02:00
if ( checkUninitVar ) {
2013-02-10 13:36:40 +01:00
if ( c - > strncpy_ | | c - > memset_nonzero ) {
2013-02-10 23:53:01 +01:00
if ( ! Token : : Match ( c - > var - > typeStartToken ( ) , " char|wchar_t " ) ) {
2013-02-10 13:36:40 +01:00
continue ;
}
2012-05-25 13:40:18 +02:00
checkUninitVar - > uninitstringError ( tok , c - > var - > name ( ) , c - > strncpy_ ) ;
2013-02-10 23:53:01 +01:00
} else if ( c - > var - > isPointer ( ) & & ! c - > var - > isArray ( ) & & c - > alloc )
2012-05-25 13:40:18 +02:00
checkUninitVar - > uninitdataError ( tok , c - > var - > name ( ) ) ;
2010-10-31 12:31:11 +01:00
else
2012-05-25 13:40:18 +02:00
checkUninitVar - > uninitvarError ( tok , c - > var - > name ( ) ) ;
2010-10-31 12:31:11 +01:00
return true ;
}
}
}
// No error found
return false ;
}
/**
* Reading variable . Use this function in situations when it is
* invalid to read the data of the variable but not the address .
* @ param checks all available checks
* @ param tok variable token
* @ return if error is found , true is returned
*/
2011-10-13 20:53:06 +02:00
static bool use ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 12:31:11 +01:00
return use ( checks , tok , 0 ) ;
}
/**
* Reading array elements . If the variable is not an array then the usage is ok .
* @ param checks all available checks
* @ param tok variable token
*/
2011-10-13 20:53:06 +02:00
static void use_array ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 12:31:11 +01:00
use ( checks , tok , 1 ) ;
}
2011-10-29 19:11:42 +02:00
/**
2012-11-03 21:21:19 +01:00
* Reading array elements with a " mem.. " function . It ' s ok if the array is not null - terminated .
2011-10-29 19:11:42 +02:00
* @ param checks all available checks
* @ param tok variable token
*/
static void use_array_mem ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
use ( checks , tok , 2 ) ;
}
2010-10-31 12:31:11 +01:00
/**
* Bad pointer usage . If the variable is not a pointer then the usage is ok .
* @ param checks all available checks
* @ param tok variable token
* @ return if error is found , true is returned
*/
2011-10-13 20:53:06 +02:00
static bool use_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2011-10-29 19:11:42 +02:00
return use ( checks , tok , 3 ) ;
2010-10-31 12:31:11 +01:00
}
/**
* Using variable . . if it ' s a dead pointer the usage is invalid .
* @ param checks all available checks
* @ param tok variable token
* @ return if error is found , true is returned
*/
2011-10-13 20:53:06 +02:00
static bool use_dead_pointer ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2011-10-29 19:11:42 +02:00
return use ( checks , tok , 4 ) ;
2010-10-31 12:31:11 +01:00
}
/**
* Using variable . . reading from uninitialized array or pointer data is invalid .
* Example : = x [ 0 ] ;
* @ param checks all available checks
* @ param tok variable token
* @ return if error is found , true is returned
*/
2011-10-13 20:53:06 +02:00
static bool use_array_or_pointer_data ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2011-10-29 19:11:42 +02:00
return use ( checks , tok , 5 ) ;
2010-10-31 12:31:11 +01:00
}
2010-11-05 19:24:14 +01:00
/**
* Parse right hand side expression in statement
* @ param tok2 start token of rhs
* @ param checks the execution paths
*/
2011-10-13 20:53:06 +02:00
void parserhs ( const Token * tok2 , std : : list < ExecutionPath * > & checks ) const {
2010-11-05 19:24:14 +01:00
// check variable usages in rhs/index
2011-10-13 20:53:06 +02:00
while ( NULL ! = ( tok2 = tok2 - > next ( ) ) ) {
2012-06-23 12:19:03 +02:00
if ( Token : : Match ( tok2 , " [;)=] " ) )
2010-11-05 19:24:14 +01:00
break ;
if ( Token : : Match ( tok2 , " %var% ( " ) )
break ;
if ( tok2 - > varId ( ) & &
! Token : : Match ( tok2 - > previous ( ) , " &|:: " ) & &
2011-05-05 21:26:18 +02:00
! Token : : simpleMatch ( tok2 - > tokAt ( - 2 ) , " & ( " ) & &
2011-10-13 20:53:06 +02:00
! Token : : simpleMatch ( tok2 - > next ( ) , " = " ) ) {
2010-11-05 19:24:14 +01:00
// Multiple assignments..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > next ( ) , " .|[ " ) ) {
2010-11-05 19:24:14 +01:00
const Token * tok3 = tok2 ;
2011-10-13 20:53:06 +02:00
while ( tok3 ) {
2010-11-30 18:40:36 +01:00
if ( Token : : Match ( tok3 - > next ( ) , " . %var% " ) )
tok3 = tok3 - > tokAt ( 2 ) ;
else if ( tok3 - > strAt ( 1 ) = = " [ " )
tok3 = tok3 - > next ( ) - > link ( ) ;
else
break ;
}
2010-12-01 18:05:57 +01:00
if ( tok3 & & tok3 - > strAt ( 1 ) = = " = " )
2010-11-05 19:24:14 +01:00
continue ;
}
bool foundError ;
if ( tok2 - > previous ( ) - > str ( ) = = " * " | | tok2 - > next ( ) - > str ( ) = = " [ " )
foundError = use_array_or_pointer_data ( checks , tok2 ) ;
else
foundError = use ( checks , tok2 ) ;
// prevent duplicate error messages
2011-10-13 20:53:06 +02:00
if ( foundError ) {
2010-11-05 19:24:14 +01:00
bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
}
}
}
2010-10-31 12:31:11 +01:00
/** parse tokens. @sa ExecutionPath::parse */
2011-10-13 20:53:06 +02:00
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const {
2010-10-31 12:31:11 +01:00
// Variable declaration..
2012-05-25 13:40:18 +02:00
if ( tok . varId ( ) & & Token : : Match ( & tok , " %var% [[;] " ) ) {
2013-02-02 16:27:12 +01:00
const Variable * var2 = tok . variable ( ) ;
2012-06-26 18:28:41 +02:00
if ( var2 & & var2 - > nameToken ( ) = = & tok & & ! var2 - > isStatic ( ) & & ! var2 - > isExtern ( ) & & ! var2 - > isConst ( ) ) {
2012-05-25 16:28:32 +02:00
if ( tok . linkAt ( 1 ) ) { // array
2012-06-08 16:17:55 +02:00
const Token * endtok = tok . next ( ) ;
while ( endtok - > link ( ) )
endtok = endtok - > link ( ) - > next ( ) ;
if ( endtok - > str ( ) ! = " ; " )
2012-05-25 16:28:32 +02:00
return & tok ;
}
2012-05-25 13:40:18 +02:00
const Scope * parent = var2 - > scope ( ) - > nestedIn ;
while ( parent ) {
for ( std : : list < Variable > : : const_iterator j = parent - > varlist . begin ( ) ; j ! = parent - > varlist . end ( ) ; + + j ) {
if ( j - > name ( ) = = var2 - > name ( ) ) {
ExecutionPath : : bailOutVar ( checks , j - > varId ( ) ) ; // If there is a variable with the same name in other scopes, this might cause false positives, if there are unexpanded macros
break ;
}
}
parent = parent - > nestedIn ;
}
2010-10-31 12:31:11 +01:00
2012-05-25 13:40:18 +02:00
if ( var2 - > isPointer ( ) )
2012-06-22 19:57:07 +02:00
checks . push_back ( new UninitVar ( owner , var2 , symbolDatabase , isC ) ) ;
2012-05-25 13:40:18 +02:00
else if ( var2 - > typeEndToken ( ) - > str ( ) ! = " > " ) {
2012-06-27 20:44:19 +02:00
bool stdtype = false ; // TODO: change to isC to handle unknown types better
2012-05-25 13:40:18 +02:00
for ( const Token * tok2 = var2 - > typeStartToken ( ) ; tok2 ! = var2 - > nameToken ( ) ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > isStandardType ( ) ) {
2012-06-22 19:57:07 +02:00
stdtype = true ;
2012-05-25 13:40:18 +02:00
break ;
}
2010-10-31 12:31:11 +01:00
}
2012-06-22 19:57:07 +02:00
if ( stdtype & & ( ! var2 - > isArray ( ) | | var2 - > nameToken ( ) - > linkAt ( 1 ) - > strAt ( 1 ) = = " ; " ) )
checks . push_back ( new UninitVar ( owner , var2 , symbolDatabase , isC ) ) ;
2010-10-31 12:31:11 +01:00
}
2012-05-25 13:40:18 +02:00
return & tok ;
2010-10-31 12:31:11 +01:00
}
}
2011-10-13 20:53:06 +02:00
if ( tok . str ( ) = = " return " ) {
2011-09-20 21:00:05 +02:00
// is there assignment or ternary operator in the return statement?
2011-07-24 22:41:40 +02:00
bool assignment = false ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok . next ( ) ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) ) {
2012-06-23 16:06:20 +02:00
if ( tok2 - > str ( ) = = " = " | | ( ! isC & & tok2 - > str ( ) = = " >> " ) | | Token : : Match ( tok2 , " (|, & " ) ) {
2011-07-24 22:41:40 +02:00
assignment = true ;
break ;
}
2012-06-23 16:06:20 +02:00
if ( Token : : Match ( tok2 , " [(,] &| %var% [,)] " ) ) {
tok2 = tok2 - > next ( ) ;
if ( ! tok2 - > isName ( ) )
tok2 = tok2 - > next ( ) ;
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
2011-07-24 22:41:40 +02:00
}
2011-07-24 22:26:11 +02:00
2011-10-13 20:53:06 +02:00
if ( ! assignment ) {
for ( const Token * tok2 = tok . next ( ) ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) ) {
2011-07-24 22:41:40 +02:00
if ( tok2 - > isName ( ) & & tok2 - > strAt ( 1 ) = = " ( " )
tok2 = tok2 - > next ( ) - > link ( ) ;
else if ( tok2 - > varId ( ) )
use ( checks , tok2 ) ;
}
2011-07-24 22:26:11 +02:00
}
}
2011-10-13 20:53:06 +02:00
if ( tok . varId ( ) ) {
2010-11-12 17:38:25 +01:00
// array variable passed as function parameter..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . previous ( ) , " [(,] %var% [+-,)] " ) ) {
2012-01-21 20:42:41 +01:00
// skip ')'..
const Token * tok2 = tok . next ( ) ;
while ( tok2 & & tok2 - > str ( ) = = " ) " )
tok2 = tok2 - > next ( ) ;
// variable is assigned like: "( %var% ) .. ="
if ( Token : : Match ( tok . previous ( ) , " ( %var% ) " ) & & tok2 & & tok2 - > str ( ) = = " = " )
2011-10-30 18:19:09 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
2012-10-13 14:59:34 +02:00
else if ( tok . strAt ( - 2 ) ! = " > " | | ! tok . linkAt ( - 2 ) )
2011-10-30 18:19:09 +01:00
use ( checks , & tok ) ;
2010-12-18 10:06:21 +01:00
//use_array(checks, &tok);
2010-11-12 17:38:25 +01:00
return & tok ;
}
2010-10-31 12:31:11 +01:00
// Used..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . previous ( ) , " [[(,+-*/|=] %var% ]|)|,|;|%op% " ) ) {
2012-03-16 17:28:05 +01:00
// Taking address of array..
std : : list < ExecutionPath * > : : const_iterator it ;
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
UninitVar * c = dynamic_cast < UninitVar * > ( * it ) ;
if ( c & & c - > varId = = tok . varId ( ) ) {
2012-05-25 13:40:18 +02:00
if ( c - > var - > isArray ( ) )
2012-03-16 17:28:05 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
break ;
}
}
2011-09-03 18:53:14 +02:00
// initialize reference variable
if ( Token : : Match ( tok . tokAt ( - 3 ) , " & %var% = " ) )
bailOutVar ( checks , tok . varId ( ) ) ;
else
use ( checks , & tok ) ;
2010-10-31 12:31:11 +01:00
return & tok ;
}
2012-04-25 09:56:07 +02:00
if ( ( tok . previous ( ) & & tok . previous ( ) - > type ( ) = = Token : : eIncDecOp ) | | ( tok . next ( ) & & tok . next ( ) - > type ( ) = = Token : : eIncDecOp ) ) {
2010-10-31 12:31:11 +01:00
use ( checks , & tok ) ;
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . previous ( ) , " [;{}] %var% [=[.] " ) ) {
if ( tok . next ( ) - > str ( ) = = " . " ) {
if ( use_dead_pointer ( checks , & tok ) ) {
2010-10-31 12:31:11 +01:00
return & tok ;
}
2011-10-13 20:53:06 +02:00
} else {
2010-11-05 19:24:14 +01:00
const Token * tok2 = tok . next ( ) ;
2012-04-24 19:50:54 +02:00
if ( tok2 - > str ( ) = = " [ " ) {
const Token * tok3 = tok2 - > link ( ) ;
while ( Token : : simpleMatch ( tok3 , " ] [ " ) )
tok3 = tok3 - > next ( ) - > link ( ) ;
// Possible initialization
if ( Token : : simpleMatch ( tok3 , " ] >> " ) )
2011-04-26 20:26:09 +02:00
return & tok ;
2012-04-24 19:50:54 +02:00
if ( Token : : simpleMatch ( tok3 , " ] = " ) ) {
if ( use_dead_pointer ( checks , & tok ) ) {
return & tok ;
}
parserhs ( tok2 , checks ) ;
tok2 = tok3 - > next ( ) ;
}
2010-10-31 12:31:11 +01:00
}
2012-04-24 19:50:54 +02:00
2010-11-05 19:24:14 +01:00
parserhs ( tok2 , checks ) ;
2010-10-31 12:31:11 +01:00
}
// pointer aliasing?
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . tokAt ( 2 ) , " %var% ; " ) ) {
2010-10-31 12:31:11 +01:00
pointer_assignment ( checks , & tok , tok . tokAt ( 2 ) ) ;
}
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " ( " ) ) {
2010-10-31 12:31:11 +01:00
use_pointer ( checks , & tok ) ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [;{}] * " ) ) {
if ( Token : : simpleMatch ( tok . next ( ) , " = " ) ) {
2010-11-05 17:04:41 +01:00
// is the pointer used in the rhs?
bool used = false ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok . tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-11-05 17:04:41 +01:00
if ( Token : : Match ( tok2 , " [,;=(] " ) )
break ;
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " * %varid% " , tok . varId ( ) ) ) {
2010-11-05 17:04:41 +01:00
used = true ;
break ;
}
}
if ( used )
use_pointer ( checks , & tok ) ;
else
init_pointer ( checks , & tok ) ;
2011-10-13 20:53:06 +02:00
} else {
2010-10-31 12:31:11 +01:00
use_pointer ( checks , & tok ) ;
2010-11-05 17:04:41 +01:00
}
2010-10-31 12:31:11 +01:00
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . next ( ) , " = malloc|kmalloc " ) | | Token : : simpleMatch ( tok . next ( ) , " = new char [ " ) ) {
2010-10-31 12:31:11 +01:00
alloc_pointer ( checks , tok . varId ( ) ) ;
2011-11-13 13:10:59 +01:00
if ( tok . strAt ( 3 ) = = " ( " )
2010-10-31 12:31:11 +01:00
return tok . tokAt ( 3 ) ;
}
2012-12-18 19:02:30 +01:00
else if ( ( ! isC & & ( Token : : Match ( tok . previous ( ) , " <<|>> " ) | | Token : : Match ( tok . previous ( ) , " [ ; { } ] % var % < < " ))) ||
Token : : simpleMatch ( tok . next ( ) , " = " ) ) {
2011-09-04 12:53:53 +02:00
// TODO: Don't bail out for "<<" and ">>" if these are
// just computations
2010-10-31 12:31:11 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) ) {
2010-10-31 12:31:11 +01:00
const Token * tok2 = tok . next ( ) - > link ( ) ;
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok2 ? tok2 - > next ( ) : 0 , " = " ) ) {
2010-10-31 12:31:11 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
return & tok ;
}
}
if ( Token : : simpleMatch ( tok . previous ( ) , " delete " ) | |
2011-10-13 20:53:06 +02:00
Token : : simpleMatch ( tok . tokAt ( - 3 ) , " delete [ ] " ) ) {
2010-10-31 12:31:11 +01:00
dealloc_pointer ( checks , & tok ) ;
return & tok ;
}
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " %var% ( " ) & & uvarFunctions . find ( tok . str ( ) ) = = uvarFunctions . end ( ) ) {
2010-12-30 21:30:46 +01:00
// sizeof/typeof doesn't dereference. A function name that is all uppercase
// might be an unexpanded macro that uses sizeof/typeof
2011-01-05 20:44:04 +01:00
if ( Token : : Match ( & tok , " sizeof|typeof ( " ) )
2010-10-31 12:31:11 +01:00
return tok . next ( ) - > link ( ) ;
// deallocate pointer
2011-09-28 20:46:09 +02:00
if ( Token : : Match ( & tok , " free|kfree|fclose ( %var% ) " ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( & tok , " realloc ( %var% " ) ) {
2010-10-31 12:31:11 +01:00
dealloc_pointer ( checks , tok . tokAt ( 2 ) ) ;
return tok . tokAt ( 3 ) ;
}
// parse usage..
{
2012-05-26 15:49:40 +02:00
std : : list < const Token * > var1 ;
CheckNullPointer : : parseFunctionCall ( tok , var1 , 1 ) ;
for ( std : : list < const Token * > : : const_iterator it = var1 . begin ( ) ; it ! = var1 . end ( ) ; + + it ) {
2011-12-23 08:44:28 +01:00
// does iterator point at first function parameter?
const bool firstPar ( * it = = tok . tokAt ( 2 ) ) ;
2011-10-29 19:11:42 +02:00
// is function memset/memcpy/etc?
if ( tok . str ( ) . compare ( 0 , 3 , " mem " ) = = 0 )
use_array_mem ( checks , * it ) ;
2011-12-23 08:44:28 +01:00
// second parameter for strncpy/strncat/etc
else if ( ! firstPar & & tok . str ( ) . compare ( 0 , 4 , " strn " ) = = 0 )
use_array_mem ( checks , * it ) ;
2011-10-29 19:11:42 +02:00
else
use_array ( checks , * it ) ;
2011-02-26 20:08:37 +01:00
use_dead_pointer ( checks , * it ) ;
}
2010-10-31 12:31:11 +01:00
// Using uninitialized pointer is bad if using null pointer is bad
std : : list < const Token * > var2 ;
CheckNullPointer : : parseFunctionCall ( tok , var2 , 0 ) ;
2011-10-13 20:53:06 +02:00
for ( std : : list < const Token * > : : const_iterator it = var2 . begin ( ) ; it ! = var2 . end ( ) ; + + it ) {
2012-05-26 15:49:40 +02:00
if ( std : : find ( var1 . begin ( ) , var1 . end ( ) , * it ) = = var1 . end ( ) )
2010-10-31 12:31:11 +01:00
use_dead_pointer ( checks , * it ) ;
}
}
2012-11-03 21:21:19 +01:00
// strncpy doesn't null-terminate first parameter
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " strncpy ( %var% , " ) ) {
if ( Token : : Match ( tok . tokAt ( 4 ) , " %str% , " ) ) {
if ( Token : : Match ( tok . tokAt ( 6 ) , " %num% ) " ) ) {
2010-12-31 09:51:27 +01:00
const std : : size_t len = Token : : getStrLength ( tok . tokAt ( 4 ) ) ;
2010-11-20 10:05:33 +01:00
const MathLib : : bigint sz = MathLib : : toLongNumber ( tok . strAt ( 6 ) ) ;
2011-10-13 20:53:06 +02:00
if ( sz > = 0 & & len > = static_cast < unsigned long > ( sz ) ) {
2010-10-31 12:31:11 +01:00
init_strncpy ( checks , tok . tokAt ( 2 ) ) ;
return tok . next ( ) - > link ( ) ;
}
}
2011-10-13 20:53:06 +02:00
} else {
2010-10-31 12:31:11 +01:00
init_strncpy ( checks , tok . tokAt ( 2 ) ) ;
return tok . next ( ) - > link ( ) ;
}
}
2011-09-05 19:42:48 +02:00
// memset (not zero terminated)..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " memset ( %var% , !!0 , %num% ) " ) ) {
2011-09-05 19:42:48 +02:00
init_memset_nonzero ( checks , tok . tokAt ( 2 ) ) ;
return tok . next ( ) - > link ( ) ;
}
2011-12-13 21:42:38 +01:00
if ( Token : : Match ( & tok , " asm ( %str% ) " ) ) {
2010-10-31 12:31:11 +01:00
ExecutionPath : : bailOut ( checks ) ;
return & tok ;
}
// is the variable passed as a parameter to some function?
unsigned int parlevel = 0 ;
std : : set < unsigned int > bailouts ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok . next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-10-31 12:31:11 +01:00
if ( tok2 - > str ( ) = = " ( " )
+ + parlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " ) " ) {
2010-10-31 12:31:11 +01:00
if ( parlevel < = 1 )
break ;
- - parlevel ;
}
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok2 , " sizeof|typeof ( " ) ) {
2010-10-31 12:31:11 +01:00
tok2 = tok2 - > next ( ) - > link ( ) ;
if ( ! tok2 )
break ;
}
2010-12-30 21:30:46 +01:00
// ticket #2367 : unexpanded macro that uses sizeof|typeof?
2012-06-21 19:00:53 +02:00
else if ( Token : : Match ( tok2 , " %type% ( " ) & & tok2 - > isUpperCaseName ( ) ) {
2010-12-30 21:30:46 +01:00
tok2 = tok2 - > next ( ) - > link ( ) ;
if ( ! tok2 )
break ;
}
2011-10-13 20:53:06 +02:00
else if ( tok2 - > varId ( ) ) {
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [(,] * " ) | | Token : : Match ( tok2 - > next ( ) , " . %var% " ) ) {
2011-01-05 20:44:04 +01:00
// find function call..
const Token * functionCall = tok2 ;
2011-12-01 10:48:14 +01:00
while ( NULL ! = ( functionCall = functionCall ? functionCall - > previous ( ) : 0 ) ) {
2011-01-05 20:44:04 +01:00
if ( functionCall - > str ( ) = = " ( " )
break ;
if ( functionCall - > str ( ) = = " ) " )
functionCall = functionCall - > link ( ) ;
}
functionCall = functionCall ? functionCall - > previous ( ) : 0 ;
2011-10-13 20:53:06 +02:00
if ( functionCall ) {
2012-06-21 19:00:53 +02:00
if ( functionCall - > isName ( ) & & ! functionCall - > isUpperCaseName ( ) & & use_dead_pointer ( checks , tok2 ) )
2011-01-05 20:44:04 +01:00
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
2010-10-31 12:31:11 +01:00
}
// it is possible that the variable is initialized here
2010-11-13 15:10:17 +01:00
if ( Token : : Match ( tok2 - > previous ( ) , " [(,] %var% [,)] " ) )
2010-10-31 12:31:11 +01:00
bailouts . insert ( tok2 - > varId ( ) ) ;
// array initialization..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " [,(] %var% [+-] " ) ) {
2010-10-31 12:31:11 +01:00
// if var is array, bailout
2011-10-13 20:53:06 +02:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
if ( ( * it ) - > varId = = tok2 - > varId ( ) ) {
2010-10-31 12:31:11 +01:00
const UninitVar * c = dynamic_cast < const UninitVar * > ( * it ) ;
2012-05-25 13:40:18 +02:00
if ( c & & ( c - > var - > isArray ( ) | | ( c - > var - > isPointer ( ) & & c - > alloc ) ) )
2010-10-31 12:31:11 +01:00
bailouts . insert ( tok2 - > varId ( ) ) ;
break ;
}
}
}
}
}
for ( std : : set < unsigned int > : : const_iterator it = bailouts . begin ( ) ; it ! = bailouts . end ( ) ; + + it )
ExecutionPath : : bailOutVar ( checks , * it ) ;
}
// function call via function pointer
2011-10-30 17:41:05 +01:00
if ( Token : : Match ( & tok , " ( * %var% ) ( " ) | |
2011-10-30 17:22:30 +01:00
( Token : : Match ( & tok , " ( *| %var% .|:: " ) & & Token : : Match ( tok . link ( ) - > tokAt ( - 2 ) , " .|:: %var% ) ( " ) ) ) {
2010-10-31 12:31:11 +01:00
// is the variable passed as a parameter to some function?
2012-04-21 23:05:37 +02:00
const Token * tok2 = tok . link ( ) - > next ( ) ;
2012-05-07 15:34:47 +02:00
for ( const Token * const end2 = tok2 - > link ( ) ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
2012-04-21 23:05:37 +02:00
if ( tok2 - > varId ( ) ) {
2010-10-31 12:31:11 +01:00
// it is possible that the variable is initialized here
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
}
}
2011-10-13 20:53:06 +02:00
if ( tok . str ( ) = = " return " ) {
2010-10-31 12:31:11 +01:00
// Todo: if (!array && ..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . next ( ) , " %var% ; " ) ) {
2010-10-31 12:31:11 +01:00
use ( checks , tok . next ( ) ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok . next ( ) , " %var% [ " ) ) {
2010-10-31 12:31:11 +01:00
use_array_or_pointer_data ( checks , tok . next ( ) ) ;
}
}
2011-10-13 20:53:06 +02:00
if ( tok . varId ( ) ) {
if ( Token : : simpleMatch ( tok . previous ( ) , " = " ) ) {
if ( Token : : Match ( tok . tokAt ( - 3 ) , " & %var% = " ) ) {
2010-10-31 12:31:11 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " . %var% = " ) ) {
if ( ! Token : : Match ( tok . tokAt ( - 3 ) , " [;{}] %var% = " ) ) {
2010-10-31 12:31:11 +01:00
use ( checks , & tok ) ;
return & tok ;
}
const unsigned int varid2 = tok . tokAt ( - 2 ) - > varId ( ) ;
2011-10-13 20:53:06 +02:00
if ( varid2 ) {
2010-10-31 12:31:11 +01:00
{
use ( checks , & tok ) ;
return & tok ;
}
}
}
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " . " ) ) {
2010-11-27 17:34:54 +01:00
bailOutVar ( checks , tok . varId ( ) ) ;
2010-10-31 12:31:11 +01:00
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok . next ( ) , " [ " ) ) {
2010-10-31 12:31:11 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok . tokAt ( - 2 ) , " [,(=] * " ) ) {
2010-10-31 12:31:11 +01:00
use_pointer ( checks , & tok ) ;
return & tok ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok . previous ( ) , " & " ) ) {
2010-10-31 12:31:11 +01:00
ExecutionPath : : bailOutVar ( checks , tok . varId ( ) ) ;
}
}
// Parse "for"
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " [;{}] for ( " ) ) {
2010-10-31 12:31:11 +01:00
// initialized variables
std : : set < unsigned int > varid1 ;
varid1 . insert ( 0 ) ;
// Parse token
const Token * tok2 ;
// parse setup
2011-10-13 20:53:06 +02:00
for ( tok2 = tok . tokAt ( 3 ) ; tok2 ! = tok . link ( ) ; tok2 = tok2 - > next ( ) ) {
2010-10-31 12:31:11 +01:00
if ( tok2 - > str ( ) = = " ; " )
break ;
if ( tok2 - > varId ( ) )
varid1 . insert ( tok2 - > varId ( ) ) ;
}
2010-11-24 18:08:21 +01:00
if ( tok2 = = tok . link ( ) )
return & tok ;
2010-10-31 12:31:11 +01:00
// parse condition
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " ; %var% <|<=|>=|> %num% ; " ) ) {
2010-10-31 12:31:11 +01:00
// If the variable hasn't been initialized then call "use"
if ( varid1 . find ( tok2 - > next ( ) - > varId ( ) ) = = varid1 . end ( ) )
use ( checks , tok2 - > next ( ) ) ;
}
// goto stepcode
tok2 = tok2 - > next ( ) ;
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
tok2 = tok2 - > next ( ) ;
// parse the stepcode
if ( Token : : Match ( tok2 , " ; ++|-- %var% ) { " ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( tok2 , " ; %var% ++|-- ) { " ) ) {
2010-10-31 12:31:11 +01:00
// get id of variable..
unsigned int varid = tok2 - > next ( ) - > varId ( ) ;
if ( ! varid )
varid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
// Check that the variable hasn't been initialized and
// that it isn't initialized in the body..
2011-10-13 20:53:06 +02:00
if ( varid1 . find ( varid ) = = varid1 . end ( ) ) {
2012-01-15 12:31:49 +01:00
for ( const Token * tok3 = tok2 - > tokAt ( 5 ) ; tok3 & & tok3 ! = tok2 - > linkAt ( 4 ) ; tok3 = tok3 - > next ( ) ) {
2011-10-13 20:53:06 +02:00
if ( tok3 - > varId ( ) = = varid ) {
2010-10-31 12:31:11 +01:00
varid = 0 ; // variable is used.. maybe it's initialized. clear the variable id.
break ;
}
}
// If the variable isn't initialized in the body call "use"
2011-10-13 20:53:06 +02:00
if ( varid ! = 0 ) {
2010-10-31 12:31:11 +01:00
// goto variable
tok2 = tok2 - > next ( ) ;
if ( ! tok2 - > varId ( ) )
tok2 = tok2 - > next ( ) ;
// call "use"
use ( checks , tok2 ) ;
}
}
}
}
return & tok ;
}
2011-10-13 20:53:06 +02:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks ) {
2010-10-31 12:31:11 +01:00
if ( tok . varId ( ) & & Token : : Match ( & tok , " %var% <|<=|==|!=|) " ) )
use ( checks , & tok ) ;
2012-07-17 07:03:40 +02:00
else if ( Token : : Match ( & tok , " !| %var% [ " ) & & ! Token : : simpleMatch ( skipBrackets ( tok . next ( ) ) , " = " ) )
2010-10-31 12:31:11 +01:00
use_array_or_pointer_data ( checks , tok . str ( ) = = " ! " ? tok . next ( ) : & tok ) ;
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( & tok , " !| %var% ( " ) ) {
2011-10-29 19:11:42 +02:00
const Token * const ftok = ( tok . str ( ) = = " ! " ) ? tok . next ( ) : & tok ;
2012-05-26 15:49:40 +02:00
std : : list < const Token * > var1 ;
CheckNullPointer : : parseFunctionCall ( * ftok , var1 , 1 ) ;
for ( std : : list < const Token * > : : const_iterator it = var1 . begin ( ) ; it ! = var1 . end ( ) ; + + it ) {
2011-10-29 19:11:42 +02:00
// is function memset/memcpy/etc?
if ( ftok - > str ( ) . compare ( 0 , 3 , " mem " ) = = 0 )
use_array_mem ( checks , * it ) ;
else
use_array ( checks , * it ) ;
}
2010-10-31 12:31:11 +01:00
}
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( & tok , " ! %var% ) " )) {
2010-10-31 12:31:11 +01:00
use ( checks , & tok ) ;
return false ;
}
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2011-10-13 20:53:06 +02:00
void parseLoopBody ( const Token * tok , std : : list < ExecutionPath * > & checks ) const {
while ( tok ) {
2010-10-31 12:31:11 +01:00
if ( tok - > str ( ) = = " { " | | tok - > str ( ) = = " } " | | tok - > str ( ) = = " for " )
return ;
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok , " if ( " ) ) {
2010-12-23 09:15:45 +01:00
// bail out all variables that are used in the condition
2012-05-07 15:34:47 +02:00
const Token * const end2 = tok - > linkAt ( 1 ) ;
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
2012-04-21 23:05:37 +02:00
if ( tok2 - > varId ( ) )
2010-12-23 09:15:45 +01:00
ExecutionPath : : bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
}
2010-10-31 12:31:11 +01:00
const Token * next = parse ( * tok , checks ) ;
2010-11-13 08:03:59 +01:00
tok = next - > next ( ) ;
2010-10-31 12:31:11 +01:00
}
}
public :
/** Functions that don't handle uninitialized variables well */
static std : : set < std : : string > uvarFunctions ;
2011-10-13 20:53:06 +02:00
static void analyseFunctions ( const Token * const tokens , std : : set < std : : string > & func ) {
for ( const Token * tok = tokens ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " ) {
2010-10-31 12:31:11 +01:00
tok = tok - > link ( ) ;
continue ;
}
2011-10-13 20:53:06 +02:00
if ( tok - > str ( ) ! = " :: " & & Token : : Match ( tok - > next ( ) , " %var% ( %type% " ) ) {
2011-11-20 14:22:39 +01:00
if ( ! Token : : Match ( tok - > linkAt ( 2 ) , " ) [{;] " ) )
2010-10-31 12:31:11 +01:00
continue ;
const Token * tok2 = tok - > tokAt ( 3 ) ;
2011-10-13 20:53:06 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " ) " ) {
2010-10-31 12:31:11 +01:00
if ( tok2 - > str ( ) = = " , " )
tok2 = tok2 - > next ( ) ;
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " %type% %var% ,|) " ) & & tok2 - > isStandardType ( ) ) {
2010-10-31 12:31:11 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
continue ;
}
2011-10-13 20:53:06 +02:00
if ( tok2 - > isStandardType ( ) & & Token : : Match ( tok2 , " %type% & %var% ,|) " ) ) {
2010-10-31 12:31:11 +01:00
const unsigned int varid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
// flags for read/write
bool r = false , w = false ;
// check how the variable is used in the function
unsigned int indentlevel = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok3 = tok2 ; tok3 ; tok3 = tok3 - > next ( ) ) {
2010-10-31 12:31:11 +01:00
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel ;
2011-10-13 20:53:06 +02:00
else if ( tok3 - > str ( ) = = " } " ) {
2010-10-31 12:31:11 +01:00
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
2011-10-13 20:53:06 +02:00
} else if ( indentlevel = = 0 & & tok3 - > str ( ) = = " ; " )
2010-10-31 12:31:11 +01:00
break ;
2011-10-13 20:53:06 +02:00
else if ( indentlevel > = 1 & & tok3 - > varId ( ) = = varid ) {
2012-04-25 09:56:07 +02:00
if ( tok3 - > previous ( ) - > type ( ) = = Token : : eIncDecOp | |
tok3 - > next ( ) - > type ( ) = = Token : : eIncDecOp ) {
2010-10-31 12:31:11 +01:00
r = true ;
}
2011-10-13 20:53:06 +02:00
else {
2010-10-31 12:31:11 +01:00
w = true ;
break ;
}
}
}
if ( ! r | | w )
break ;
tok2 = tok2 - > tokAt ( 3 ) ;
continue ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " const %type% &|*| const| %var% ,|) " ) & & tok2 - > next ( ) - > isStandardType ( ) ) {
2010-10-31 12:31:11 +01:00
tok2 = tok2 - > tokAt ( 3 ) ;
while ( tok2 - > isName ( ) )
tok2 = tok2 - > next ( ) ;
continue ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " const %type% %var% [ ] ,|) " ) & & tok2 - > next ( ) - > isStandardType ( ) ) {
2010-11-12 17:14:37 +01:00
tok2 = tok2 - > tokAt ( 5 ) ;
continue ;
}
2011-07-27 10:34:12 +02:00
/// @todo enable this code. if pointer is written in function then dead pointer is invalid but valid pointer is ok.
/*
2011-07-04 21:04:32 +02:00
if ( Token : : Match ( tok2 , " const| struct| %type% * %var% ,|) " ) )
{
while ( tok2 - > isName ( ) )
tok2 = tok2 - > next ( ) ;
tok2 = tok2 - > tokAt ( 2 ) ;
continue ;
}
2011-07-27 10:34:12 +02:00
*/
2011-07-04 21:04:32 +02:00
2010-10-31 12:31:11 +01:00
break ;
}
// found simple function..
2011-07-28 08:12:21 +02:00
if ( tok2 & & tok2 - > link ( ) = = tok - > tokAt ( 2 ) )
2010-10-31 12:31:11 +01:00
func . insert ( tok - > next ( ) - > str ( ) ) ;
}
}
}
} ;
/** Functions that don't handle uninitialized variables well */
std : : set < std : : string > UninitVar : : uvarFunctions ;
/// @}
2012-12-27 11:51:12 +01:00
void CheckUninitVar : : analyse ( const Token * tokens , std : : set < std : : string > & func ) const
2010-10-31 12:31:11 +01:00
{
UninitVar : : analyseFunctions ( tokens , func ) ;
}
void CheckUninitVar : : saveAnalysisData ( const std : : set < std : : string > & data ) const
{
UninitVar : : uvarFunctions . insert ( data . begin ( ) , data . end ( ) ) ;
}
void CheckUninitVar : : executionPaths ( )
{
// check if variable is accessed uninitialized..
{
// no writing if multiple threads are used (TODO: thread safe analysis?)
if ( _settings - > _jobs = = 1 )
UninitVar : : analyseFunctions ( _tokenizer - > tokens ( ) , UninitVar : : uvarFunctions ) ;
2012-06-22 19:57:07 +02:00
UninitVar c ( this , _tokenizer - > getSymbolDatabase ( ) , _tokenizer - > isC ( ) ) ;
2012-01-26 16:50:59 +01:00
checkExecutionPaths ( _tokenizer - > getSymbolDatabase ( ) , & c ) ;
2010-10-31 12:31:11 +01:00
}
}
2011-12-13 21:57:27 +01:00
void CheckUninitVar : : check ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2013-01-26 07:28:11 +01:00
std : : list < Scope > : : const_iterator scope ;
2011-12-13 21:57:27 +01:00
2013-01-26 07:28:11 +01:00
// check every executable scope
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
if ( scope - > isExecutable ( ) ) {
checkScope ( & * scope ) ;
2011-12-13 21:57:27 +01:00
}
}
}
2012-05-25 13:40:18 +02:00
void CheckUninitVar : : checkScope ( const Scope * scope )
2011-12-13 21:57:27 +01:00
{
2012-05-25 13:40:18 +02:00
for ( std : : list < Variable > : : const_iterator i = scope - > varlist . begin ( ) ; i ! = scope - > varlist . end ( ) ; + + i ) {
2013-02-15 18:13:47 +01:00
if ( ( _tokenizer - > isCPP ( ) & & i - > type ( ) & & ! i - > isPointer ( ) & & i - > type ( ) - > needInitialization ! = Scope : : True ) | |
i - > isStatic ( ) | | i - > isExtern ( ) | | i - > isConst ( ) | | i - > isArray ( ) | | i - > isReference ( ) )
2012-05-25 13:40:18 +02:00
continue ;
if ( i - > nameToken ( ) - > strAt ( 1 ) = = " ( " )
continue ;
bool forHead = false ; // Don't check variables declared in header of a for loop
for ( const Token * tok = i - > typeStartToken ( ) ; tok ; tok = tok - > previous ( ) ) {
if ( tok - > str ( ) = = " ( " ) {
forHead = true ;
break ;
2013-01-26 07:28:11 +01:00
} else if ( Token : : Match ( tok , " [{};] " ) )
2012-05-25 13:40:18 +02:00
break ;
}
if ( forHead )
continue ;
2012-06-22 16:39:39 +02:00
bool stdtype = _tokenizer - > isC ( ) ;
2012-05-25 13:40:18 +02:00
const Token * tok = i - > typeStartToken ( ) ;
2012-09-09 18:56:26 +02:00
for ( ; tok & & tok - > str ( ) ! = " ; " & & tok - > str ( ) ! = " < " ; tok = tok - > next ( ) ) {
2012-05-25 13:40:18 +02:00
if ( tok - > isStandardType ( ) )
stdtype = true ;
2012-06-19 20:04:10 +02:00
}
2012-06-22 16:26:43 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
2012-05-25 13:40:18 +02:00
if ( stdtype | | i - > isPointer ( ) )
2013-01-19 12:48:56 +01:00
checkScopeForVariable ( scope , tok , * i , NULL , NULL , " " ) ;
2013-01-18 21:26:28 +01:00
if ( Token : : Match ( i - > typeStartToken ( ) , " struct %type% %var% ; " ) ) {
2013-01-16 20:28:29 +01:00
const std : : string structname ( i - > typeStartToken ( ) - > next ( ) - > str ( ) ) ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( std : : size_t j = 0U ; j < symbolDatabase - > classAndStructScopes . size ( ) ; + + j ) {
const Scope * scope2 = symbolDatabase - > classAndStructScopes [ j ] ;
if ( scope2 - > className = = structname & & scope2 - > numConstructors = = 0U ) {
for ( std : : list < Variable > : : const_iterator it = scope2 - > varlist . begin ( ) ; it ! = scope2 - > varlist . end ( ) ; + + it )
2013-01-19 12:48:56 +01:00
checkScopeForVariable ( scope , tok , * i , NULL , NULL , it - > name ( ) ) ;
2013-01-16 20:28:29 +01:00
}
}
}
2012-05-25 13:40:18 +02:00
}
}
2013-01-25 18:20:57 +01:00
static void conditionAlwaysTrueOrFalse ( const Token * tok , const std : : map < unsigned int , int > & variableValue , bool * alwaysTrue , bool * alwaysFalse )
{
2013-02-14 12:34:18 +01:00
assert ( Token : : simpleMatch ( tok , " if ( " ) ) ;
2013-01-25 18:20:57 +01:00
const Token * vartok = tok - > tokAt ( 2 ) ;
const bool NOT ( vartok - > str ( ) = = " ! " ) ;
if ( NOT )
vartok = vartok - > next ( ) ;
while ( Token : : Match ( vartok , " %var% . %var% " ) )
vartok = vartok - > tokAt ( 2 ) ;
std : : map < unsigned int , int > : : const_iterator it = variableValue . find ( vartok - > varId ( ) ) ;
if ( it = = variableValue . end ( ) )
return ;
// always true
if ( Token : : Match ( vartok , " %var% %oror%|) " ) ) {
if ( NOT )
* alwaysTrue = bool ( it - > second = = 0 ) ;
else
* alwaysTrue = bool ( it - > second ! = 0 ) ;
} else if ( Token : : Match ( vartok , " %var% == %num% %or%|) " )) {
* alwaysTrue = bool ( it - > second = = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
} else if ( Token : : Match ( vartok , " %var% != %num% %or%|) " )) {
* alwaysTrue = bool ( it - > second ! = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
}
// always false
if ( Token : : Match ( vartok , " %var% &&|) " ) ) {
if ( NOT )
* alwaysFalse = bool ( it - > second ! = 0 ) ;
2013-02-11 17:05:59 +01:00
else
* alwaysFalse = bool ( it - > second = = 0 ) ;
2013-01-25 18:20:57 +01:00
} else if ( Token : : Match ( vartok , " %var% == %num% &&|) " )) {
* alwaysFalse = bool ( it - > second ! = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
} else if ( Token : : Match ( vartok , " %var% != %num% &&|) " )) {
* alwaysFalse = bool ( it - > second = = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
}
}
2013-01-19 12:48:56 +01:00
bool CheckUninitVar : : checkScopeForVariable ( const Scope * scope , const Token * tok , const Variable & var , bool * const possibleInit , bool * const noreturn , const std : : string & membervar )
2012-05-25 13:40:18 +02:00
{
2011-12-26 12:36:35 +01:00
const bool suppressErrors ( possibleInit & & * possibleInit ) ;
if ( possibleInit )
* possibleInit = false ;
2011-12-13 21:57:27 +01:00
unsigned int number_of_if = 0 ;
2012-12-24 19:11:13 +01:00
// variable values
std : : map < unsigned int , int > variableValue ;
static const int NOT_ZERO = ( 1 < < 30 ) ; // special variable value
2012-02-06 07:32:29 +01:00
2011-12-13 21:57:27 +01:00
for ( ; tok ; tok = tok - > next ( ) ) {
// End of scope..
if ( tok - > str ( ) = = " } " ) {
2011-12-26 12:36:35 +01:00
if ( number_of_if & & possibleInit )
* possibleInit = true ;
2011-12-16 19:56:13 +01:00
2011-12-13 21:57:27 +01:00
// might be a noreturn function..
2013-01-28 18:08:20 +01:00
if ( _tokenizer - > IsScopeNoReturn ( tok ) ) {
if ( noreturn )
* noreturn = true ;
2011-12-27 18:00:12 +01:00
return true ;
2013-01-28 18:08:20 +01:00
}
2011-12-13 21:57:27 +01:00
break ;
}
2011-12-26 17:52:32 +01:00
// Unconditional inner scope..
if ( tok - > str ( ) = = " { " & & Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) {
2013-01-16 20:28:29 +01:00
if ( checkScopeForVariable ( scope , tok - > next ( ) , var , possibleInit , NULL , membervar ) )
2011-12-26 17:52:32 +01:00
return true ;
tok = tok - > link ( ) ;
continue ;
}
2012-02-06 07:32:29 +01:00
// assignment with nonzero constant..
2012-02-06 19:26:28 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [;{}] %var% = - %var% ; " ) & & tok - > varId ( ) > 0 )
2012-12-24 19:11:13 +01:00
variableValue [ tok - > varId ( ) ] = NOT_ZERO ;
2012-02-06 07:32:29 +01:00
2011-12-13 21:57:27 +01:00
// Inner scope..
2011-12-28 16:49:05 +01:00
if ( Token : : simpleMatch ( tok , " if ( " ) ) {
2012-12-24 19:11:13 +01:00
bool alwaysTrue = false ;
2013-01-25 18:20:57 +01:00
bool alwaysFalse = false ;
2012-12-24 19:11:13 +01:00
2013-01-25 18:20:57 +01:00
conditionAlwaysTrueOrFalse ( tok , variableValue , & alwaysTrue , & alwaysFalse ) ;
2012-12-24 19:11:13 +01:00
2011-12-26 18:32:42 +01:00
// initialization / usage in condition..
2013-01-28 06:47:48 +01:00
if ( ! alwaysTrue & & checkIfForWhileHead ( tok - > next ( ) , var , suppressErrors , bool ( number_of_if = = 0 ) , membervar ) )
2011-12-26 18:32:42 +01:00
return true ;
2011-12-14 17:17:24 +01:00
2012-02-06 07:32:29 +01:00
// checking if a not-zero variable is zero => bail out
2012-12-24 19:11:13 +01:00
unsigned int condVarId = 0 , condVarValue = 0 ;
if ( Token : : Match ( tok , " if ( %var% ) " ) ) {
std : : map < unsigned int , int > : : const_iterator it = variableValue . find ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
if ( it ! = variableValue . end ( ) & & it - > second = = NOT_ZERO )
return true ; // this scope is not fully analysed => return true
else {
condVarId = tok - > tokAt ( 2 ) - > varId ( ) ;
condVarValue = NOT_ZERO ;
}
}
2012-02-06 07:32:29 +01:00
2011-12-13 21:57:27 +01:00
// goto the {
tok = tok - > next ( ) - > link ( ) - > next ( ) ;
2012-01-13 23:30:43 +01:00
if ( ! tok )
break ;
if ( tok - > str ( ) = = " { " ) {
bool possibleInitIf ( number_of_if > 0 | | suppressErrors ) ;
2012-11-29 18:41:48 +01:00
bool noreturnIf = false ;
2013-02-11 17:05:59 +01:00
const bool initif = ! alwaysFalse & & checkScopeForVariable ( scope , tok - > next ( ) , var , & possibleInitIf , & noreturnIf , membervar ) ;
2011-12-13 21:57:27 +01:00
2012-12-27 18:45:00 +01:00
// bail out for such code:
// if (a) x=0; // conditional initialization
// if (b) return; // cppcheck doesn't know if b can be false when a is false.
// x++; // it's possible x is always initialized
2012-12-28 11:42:50 +01:00
if ( ! alwaysTrue & & noreturnIf & & number_of_if > 0 ) {
if ( _settings - > debugwarnings ) {
std : : string condition ;
for ( const Token * tok2 = tok - > linkAt ( - 1 ) ; tok2 ! = tok ; tok2 = tok2 - > next ( ) ) {
condition + = tok2 - > str ( ) ;
if ( tok2 - > isName ( ) & & tok2 - > next ( ) - > isName ( ) )
condition + = ' ' ;
}
reportError ( tok , Severity : : debug , " debug " , " uninitialized variables: bailout. can't determine if this condition can be false when previous condition is false: " + condition ) ;
}
2012-12-27 18:45:00 +01:00
return true ;
2012-12-28 11:42:50 +01:00
}
2012-12-27 18:45:00 +01:00
2012-12-24 19:11:13 +01:00
std : : map < unsigned int , int > varValueIf ;
2013-01-28 18:08:20 +01:00
if ( ! initif & & ! noreturnIf ) {
2012-12-23 16:27:04 +01:00
for ( const Token * tok2 = tok ; tok2 & & tok2 ! = tok - > link ( ) ; tok2 = tok2 - > next ( ) ) {
2013-01-25 18:20:57 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %var% = - %var% ; " ) )
2012-12-24 19:11:13 +01:00
varValueIf [ tok2 - > next ( ) - > varId ( ) ] = NOT_ZERO ;
2013-01-25 18:20:57 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %var% = %num% ; " ) )
2012-12-24 19:11:13 +01:00
varValueIf [ tok2 - > next ( ) - > varId ( ) ] = ( int ) MathLib : : toLongNumber ( tok2 - > strAt ( 3 ) ) ;
2012-12-23 16:27:04 +01:00
}
}
2012-12-24 19:11:13 +01:00
if ( initif & & condVarId > 0U )
variableValue [ condVarId ] = condVarValue ^ NOT_ZERO ;
2012-01-13 23:30:43 +01:00
// goto the }
tok = tok - > link ( ) ;
2011-12-13 21:57:27 +01:00
2012-01-13 23:30:43 +01:00
if ( ! Token : : simpleMatch ( tok , " } else { " ) ) {
if ( initif | | possibleInitIf ) {
+ + number_of_if ;
if ( number_of_if > = 2 )
return true ;
}
} else {
// goto the {
tok = tok - > tokAt ( 2 ) ;
2011-12-13 21:57:27 +01:00
2012-01-13 23:30:43 +01:00
bool possibleInitElse ( number_of_if > 0 | | suppressErrors ) ;
2012-11-29 18:41:48 +01:00
bool noreturnElse = false ;
2013-01-16 20:28:29 +01:00
const bool initelse = checkScopeForVariable ( scope , tok - > next ( ) , var , & possibleInitElse , NULL , membervar ) ;
2011-12-13 21:57:27 +01:00
2012-12-24 19:11:13 +01:00
std : : map < unsigned int , int > varValueElse ;
2013-01-28 18:08:20 +01:00
if ( ! initelse & & ! noreturnElse ) {
2012-12-23 16:27:04 +01:00
for ( const Token * tok2 = tok ; tok2 & & tok2 ! = tok - > link ( ) ; tok2 = tok2 - > next ( ) ) {
2013-01-25 18:20:57 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %var% = - %var% ; " ) )
2012-12-24 19:11:13 +01:00
varValueElse [ tok2 - > next ( ) - > varId ( ) ] = NOT_ZERO ;
2013-01-25 18:20:57 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %var% = %num% ; " ) )
2012-12-24 19:11:13 +01:00
varValueElse [ tok2 - > next ( ) - > varId ( ) ] = ( int ) MathLib : : toLongNumber ( tok2 - > strAt ( 3 ) ) ;
2012-12-23 16:27:04 +01:00
}
}
2012-12-24 19:11:13 +01:00
2013-01-28 18:08:20 +01:00
if ( initelse & & condVarId > 0U & & ! noreturnIf & & ! noreturnElse )
2012-12-24 19:11:13 +01:00
variableValue [ condVarId ] = condVarValue ;
2012-01-13 23:30:43 +01:00
// goto the }
tok = tok - > link ( ) ;
2011-12-13 21:57:27 +01:00
2012-01-13 23:30:43 +01:00
if ( initif & & initelse )
return true ;
2011-12-13 21:57:27 +01:00
2012-11-29 18:41:48 +01:00
if ( ( initif & & noreturnElse ) | | ( initelse & & noreturnIf ) )
return true ;
2013-01-28 18:08:20 +01:00
if ( ( initif | | initelse | | possibleInitElse ) & & ! noreturnIf & & ! noreturnElse ) {
2012-01-13 23:30:43 +01:00
+ + number_of_if ;
2012-12-24 19:11:13 +01:00
variableValue . insert ( varValueIf . begin ( ) , varValueIf . end ( ) ) ;
variableValue . insert ( varValueElse . begin ( ) , varValueElse . end ( ) ) ;
2012-12-23 16:27:04 +01:00
}
2012-01-13 23:30:43 +01:00
}
2011-12-13 21:57:27 +01:00
}
}
2011-12-17 07:56:46 +01:00
// = { .. }
if ( Token : : simpleMatch ( tok , " = { " ) ) {
// end token
const Token * end = tok - > next ( ) - > link ( ) ;
// If address of variable is taken in the block then bail out
2012-05-25 13:40:18 +02:00
if ( Token : : findmatch ( tok - > tokAt ( 2 ) , " & %varid% " , end , var . varId ( ) ) )
2011-12-17 07:56:46 +01:00
return true ;
// Skip block
tok = end ;
continue ;
}
2011-12-16 18:04:10 +01:00
2011-12-17 09:51:45 +01:00
// skip sizeof / offsetof
2011-12-27 17:03:48 +01:00
if ( Token : : Match ( tok , " sizeof|typeof|offsetof|decltype ( " ) )
2011-12-17 09:51:45 +01:00
tok = tok - > next ( ) - > link ( ) ;
2012-11-30 06:30:04 +01:00
// for/while..
if ( Token : : Match ( tok , " for|while ( " ) ) {
2011-12-27 08:18:05 +01:00
// is variable initialized in for-head (don't report errors yet)?
2013-01-28 06:47:48 +01:00
if ( checkIfForWhileHead ( tok - > next ( ) , var , true , false , membervar ) )
2011-12-27 08:18:05 +01:00
return true ;
2011-12-26 18:32:42 +01:00
// goto the {
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) ;
2012-01-13 23:30:43 +01:00
if ( tok2 & & tok2 - > str ( ) = = " { " ) {
2013-01-24 19:41:15 +01:00
bool possibleinit = false ;
2013-02-11 18:31:14 +01:00
bool init = checkLoopBody ( tok2 , var , membervar , suppressErrors ) ;
2011-12-26 18:32:42 +01:00
2012-01-13 23:30:43 +01:00
// variable is initialized in the loop..
if ( possibleinit | | init )
return true ;
2011-12-26 18:32:42 +01:00
2012-01-13 23:30:43 +01:00
// is variable used in for-head?
if ( ! suppressErrors ) {
2013-01-28 06:47:48 +01:00
checkIfForWhileHead ( tok - > next ( ) , var , false , bool ( number_of_if = = 0 ) , membervar ) ;
2012-01-13 23:30:43 +01:00
}
2012-11-29 18:41:48 +01:00
// goto "}"
tok = tok2 - > link ( ) ;
2011-12-27 08:18:05 +01:00
}
2011-12-26 18:32:42 +01:00
}
2011-12-15 18:30:59 +01:00
// TODO: handle loops, try, etc
2011-12-26 18:32:42 +01:00
if ( Token : : simpleMatch ( tok , " ) { " ) | | Token : : Match ( tok , " %var% { " ) ) {
2011-12-15 20:29:57 +01:00
return true ;
}
// bailout if there is assembler code
if ( Token : : simpleMatch ( tok , " asm ( " ) ) {
return true ;
2011-12-14 18:54:03 +01:00
}
2012-11-29 18:41:48 +01:00
if ( Token : : Match ( tok , " return|break|continue|throw|goto " ) ) {
if ( noreturn )
* noreturn = true ;
2012-12-25 10:37:21 +01:00
while ( tok & & tok - > str ( ) ! = " ; " ) {
// variable is seen..
2013-01-20 17:54:32 +01:00
if ( tok - > varId ( ) = = var . varId ( ) ) {
if ( ! membervar . empty ( ) ) {
if ( Token : : Match ( tok , " %var% . %var% ;|%op% " ) & & tok - > strAt ( 2 ) = = membervar )
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
else
return true ;
}
2012-12-25 10:37:21 +01:00
// Use variable
2013-02-02 15:21:54 +01:00
else if ( ! suppressErrors & & isVariableUsage ( tok , var . isPointer ( ) , _tokenizer - > isCPP ( ) ) )
2012-12-25 10:37:21 +01:00
uninitvarError ( tok , tok - > str ( ) ) ;
else
// assume that variable is assigned
return true ;
}
2012-12-25 13:31:54 +01:00
else if ( Token : : Match ( tok , " sizeof|typeof|offsetof|decltype ( " ) )
tok = tok - > linkAt ( 1 ) ;
2012-12-25 10:37:21 +01:00
tok = tok - > next ( ) ;
}
return bool ( noreturn = = NULL ) ;
}
2011-12-13 21:57:27 +01:00
// variable is seen..
2012-09-17 15:22:51 +02:00
if ( tok - > varId ( ) = = var . varId ( ) ) {
2013-01-19 12:48:56 +01:00
if ( ! membervar . empty ( ) ) {
2013-01-24 19:41:15 +01:00
if ( isMemberVariableAssignment ( tok , membervar ) )
2013-01-17 17:21:21 +01:00
return true ;
2013-01-24 19:41:15 +01:00
2013-01-28 06:47:48 +01:00
if ( isMemberVariableUsage ( tok , var . isPointer ( ) , membervar ) )
2013-01-19 12:48:56 +01:00
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
2013-01-24 19:41:15 +01:00
2013-01-16 20:28:29 +01:00
} else {
// Use variable
2013-02-02 15:21:54 +01:00
if ( ! suppressErrors & & isVariableUsage ( tok , var . isPointer ( ) , _tokenizer - > isCPP ( ) ) )
2013-01-16 20:28:29 +01:00
uninitvarError ( tok , tok - > str ( ) ) ;
2011-12-14 06:00:17 +01:00
2013-01-16 20:28:29 +01:00
else
// assume that variable is assigned
return true ;
}
2011-12-13 21:57:27 +01:00
}
}
2012-12-25 10:37:21 +01:00
return false ;
2011-12-13 21:57:27 +01:00
}
2013-01-28 06:47:48 +01:00
bool CheckUninitVar : : checkIfForWhileHead ( const Token * startparentheses , const Variable & var , bool suppressErrors , bool isuninit , const std : : string & membervar )
2011-12-26 18:32:42 +01:00
{
2013-01-16 15:37:07 +01:00
const Token * const endpar = startparentheses - > link ( ) ;
for ( const Token * tok = startparentheses - > next ( ) ; tok & & tok ! = endpar ; tok = tok - > next ( ) ) {
2012-05-25 13:40:18 +02:00
if ( tok - > varId ( ) = = var . varId ( ) ) {
2013-01-19 12:48:56 +01:00
if ( Token : : Match ( tok , " %var% . %var% " ) ) {
2013-02-05 17:01:46 +01:00
if ( tok - > strAt ( 2 ) = = membervar ) {
if ( tok - > strAt ( 3 ) = = " = " )
return true ;
else
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
}
2013-01-19 12:48:56 +01:00
continue ;
}
2013-02-02 15:21:54 +01:00
if ( isVariableUsage ( tok , var . isPointer ( ) , _tokenizer - > isCPP ( ) ) ) {
2011-12-27 08:18:05 +01:00
if ( ! suppressErrors )
uninitvarError ( tok , tok - > str ( ) ) ;
else
continue ;
}
2011-12-26 18:32:42 +01:00
return true ;
}
if ( Token : : Match ( tok , " sizeof|decltype|offsetof ( " ) )
tok = tok - > next ( ) - > link ( ) ;
2011-12-26 18:56:40 +01:00
if ( ! isuninit & & tok - > str ( ) = = " && " )
2011-12-26 18:32:42 +01:00
suppressErrors = true ;
}
return false ;
}
2013-02-11 18:31:14 +01:00
bool CheckUninitVar : : checkLoopBody ( const Token * tok , const Variable & var , const std : : string & membervar , const bool suppressErrors )
2013-01-24 19:41:15 +01:00
{
const Token * usetok = NULL ;
assert ( tok - > str ( ) = = " { " ) ;
for ( const Token * const end = tok - > link ( ) ; tok ! = end ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) = = var . varId ( ) ) {
if ( ! membervar . empty ( ) ) {
if ( isMemberVariableAssignment ( tok , membervar ) )
return true ;
2013-01-28 06:47:48 +01:00
if ( isMemberVariableUsage ( tok , var . isPointer ( ) , membervar ) )
2013-01-24 19:41:15 +01:00
usetok = tok ;
} else {
2013-02-02 15:21:54 +01:00
if ( isVariableUsage ( tok , var . isPointer ( ) , _tokenizer - > isCPP ( ) ) )
2013-01-24 19:41:15 +01:00
usetok = tok ;
else
return true ;
}
}
2013-02-12 15:59:23 +01:00
if ( Token : : Match ( tok , " asm ( %str% ) ; " ) )
return true ;
2013-01-24 19:41:15 +01:00
}
2013-02-11 18:31:14 +01:00
if ( ! suppressErrors & & usetok ) {
2013-01-24 19:41:15 +01:00
if ( membervar . empty ( ) )
uninitvarError ( usetok , usetok - > str ( ) ) ;
else
uninitStructMemberError ( usetok , usetok - > str ( ) + " . " + membervar ) ;
return true ;
}
return false ;
}
2013-02-02 15:21:54 +01:00
bool CheckUninitVar : : isVariableUsage ( const Token * vartok , bool pointer , bool cpp )
2011-12-14 18:28:30 +01:00
{
if ( vartok - > previous ( ) - > str ( ) = = " return " )
return true ;
2012-12-20 19:45:30 +01:00
// Passing variable to function..
if ( Token : : Match ( vartok - > previous ( ) , " [(,] %var% [,)] " ) | | Token : : Match ( vartok - > tokAt ( - 2 ) , " [(,] & %var% [,)] " ) ) {
const bool address ( vartok - > previous ( ) - > str ( ) = = " & " ) ;
2013-01-16 15:37:07 +01:00
// locate start parentheses in function call..
2012-12-20 19:45:30 +01:00
int argumentNumber = 0 ;
const Token * start = vartok ;
while ( start & & ! Token : : Match ( start , " [;{}(] " ) ) {
if ( start - > str ( ) = = " ) " )
start = start - > link ( ) ;
else if ( start - > str ( ) = = " , " )
+ + argumentNumber ;
start = start - > previous ( ) ;
}
// is this a function call?
if ( start & & Token : : Match ( start - > previous ( ) , " %var% ( " ) ) {
// check how function handle uninitialized data arguments..
2013-01-31 06:41:18 +01:00
const Function * func = start - > previous ( ) - > function ( ) ;
2012-12-20 19:45:30 +01:00
if ( func ) {
const Variable * arg = func - > getArgumentVar ( argumentNumber ) ;
if ( arg ) {
const Token * argStart = arg - > typeStartToken ( ) ;
while ( argStart - > previous ( ) & & argStart - > previous ( ) - > isName ( ) )
argStart = argStart - > previous ( ) ;
2013-01-16 20:28:29 +01:00
if ( ! address & & Token : : Match ( argStart , " const| struct| %type% %var% [,)] " ) )
2012-12-20 19:45:30 +01:00
return true ;
2012-12-21 17:04:15 +01:00
if ( Token : : Match ( argStart , " const %type% & %var% [,)] " ) )
return true ;
2012-12-25 13:58:15 +01:00
if ( pointer & & ! address & & Token : : Match ( argStart , " %type% * %var% [,)] " ) )
2012-12-21 17:04:15 +01:00
return true ;
2012-12-21 19:32:56 +01:00
if ( ( pointer | | address ) & & Token : : Match ( argStart , " const %type% * %var% [,)] " ) )
2012-12-20 19:45:30 +01:00
return true ;
}
2013-01-26 08:16:53 +01:00
} else if ( Token : : Match ( start - > previous ( ) , " if|while|for " ) ) {
// control-flow statement reading the variable "by value"
return true ;
2012-12-20 19:45:30 +01:00
}
}
}
2011-12-14 18:28:30 +01:00
if ( Token : : Match ( vartok - > previous ( ) , " ++|--|%op% " ) ) {
2013-02-02 15:21:54 +01:00
if ( cpp & & vartok - > previous ( ) - > str ( ) = = " >> " ) {
2011-12-15 16:55:55 +01:00
// assume that variable is initialized
return false ;
}
2012-07-03 18:52:23 +02:00
// is there something like: ; "*((&var ..expr.. =" => the variable is assigned
if ( vartok - > previous ( ) - > str ( ) = = " & " ) {
const Token * tok2 = vartok - > tokAt ( - 2 ) ;
2012-12-28 12:32:15 +01:00
if ( tok2 & & ( tok2 - > isOp ( ) | | tok2 - > str ( ) = = " ( " ) )
return false ; // address of
2012-07-03 18:52:23 +02:00
if ( Token : : simpleMatch ( tok2 , " ) " ) )
tok2 = tok2 - > link ( ) - > previous ( ) ;
while ( tok2 & & tok2 - > str ( ) = = " ( " )
tok2 = tok2 - > previous ( ) ;
while ( tok2 & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > previous ( ) ;
if ( Token : : Match ( tok2 , " [;{}] * " ) ) {
// there is some such code before vartok: "[*]+ [(]* &"
// determine if there is a = after vartok
for ( tok2 = vartok ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( Token : : Match ( tok2 , " [;{}] " ) )
break ;
if ( tok2 - > str ( ) = = " = " )
return false ;
}
}
}
2012-01-02 11:25:13 +01:00
if ( vartok - > previous ( ) - > str ( ) ! = " & " | | ! Token : : Match ( vartok - > tokAt ( - 2 ) , " [(,=?:] " ) ) {
2011-12-14 18:28:30 +01:00
return true ;
}
}
2011-12-26 14:01:46 +01:00
bool unknown = false ;
2013-02-01 19:10:14 +01:00
if ( pointer & & CheckNullPointer : : isPointerDeRef ( vartok , unknown ) ) {
2011-12-27 10:18:49 +01:00
// function parameter?
bool functionParameter = false ;
if ( Token : : Match ( vartok - > tokAt ( - 2 ) , " %var% ( " ) | | vartok - > previous ( ) - > str ( ) = = " , " )
functionParameter = true ;
// if this is not a function parameter report this dereference as variable usage
if ( ! functionParameter )
return true ;
}
2011-12-26 14:01:46 +01:00
2013-02-02 15:21:54 +01:00
if ( cpp & & Token : : Match ( vartok - > next ( ) , " <<|>> " ) ) {
2012-12-18 19:02:30 +01:00
// Is this calculation done in rhs?
const Token * tok = vartok ;
while ( tok & & Token : : Match ( tok , " %var%|.|:: " ) )
tok = tok - > previous ( ) ;
if ( Token : : Match ( tok , " [;{}] " ) )
return false ;
2012-06-13 19:09:51 +02:00
// Is variable a known POD type then this is a variable usage,
// otherwise we assume it's not.
2013-02-02 15:21:54 +01:00
const Variable * var = vartok - > variable ( ) ;
2012-12-18 19:02:30 +01:00
return ( var & & var - > typeStartToken ( ) - > isStandardType ( ) ) ;
2012-06-13 19:09:51 +02:00
}
2012-09-26 16:15:35 +02:00
if ( Token : : Match ( vartok - > next ( ) , " ++|--|%op% " ) )
2011-12-16 20:34:44 +01:00
return true ;
2011-12-16 18:12:47 +01:00
if ( vartok - > strAt ( 1 ) = = " ] " )
2011-12-14 19:56:58 +01:00
return true ;
2011-12-14 18:28:30 +01:00
return false ;
}
2013-01-24 19:41:15 +01:00
bool CheckUninitVar : : isMemberVariableAssignment ( const Token * tok , const std : : string & membervar ) const
{
if ( Token : : Match ( tok , " %var% . %var% " ) & & tok - > strAt ( 2 ) = = membervar ) {
if ( Token : : Match ( tok - > tokAt ( 3 ) , " [=.[] " ) )
return true ;
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " [(,=] & " ) )
return true ;
else if ( Token : : Match ( tok - > previous ( ) , " %op% " ) | | Token : : Match ( tok - > previous ( ) , " [|= " ) )
; // member variable usage
else
return true ;
} else if ( tok - > strAt ( 1 ) = = " = " )
return true ;
else if ( tok - > strAt ( - 1 ) = = " & " )
return true ;
return false ;
}
2013-01-28 06:47:48 +01:00
bool CheckUninitVar : : isMemberVariableUsage ( const Token * tok , bool isPointer , const std : : string & membervar ) const
2013-01-24 19:41:15 +01:00
{
if ( isMemberVariableAssignment ( tok , membervar ) )
return false ;
if ( Token : : Match ( tok , " %var% . %var% " ) & & tok - > strAt ( 2 ) = = membervar )
return true ;
2013-02-02 15:21:54 +01:00
else if ( Token : : Match ( tok - > previous ( ) , " [(,] %var% [,)] " ) & & isVariableUsage ( tok , isPointer , _tokenizer - > isCPP ( ) ) )
2013-01-24 19:41:15 +01:00
return true ;
return false ;
}
2011-12-13 21:57:27 +01:00
2011-09-05 19:42:48 +02:00
void CheckUninitVar : : uninitstringError ( const Token * tok , const std : : string & varname , bool strncpy_ )
2010-10-31 12:31:11 +01:00
{
2012-11-03 21:21:19 +01:00
reportError ( tok , Severity : : error , " uninitstring " , " Dangerous usage of ' " + varname + " ' " + ( strncpy_ ? " (strncpy doesn't always null-terminate it). " : " (not null-terminated). " ) ) ;
2010-10-31 12:31:11 +01:00
}
void CheckUninitVar : : uninitdataError ( const Token * tok , const std : : string & varname )
{
2012-11-01 18:40:20 +01:00
reportError ( tok , Severity : : error , " uninitdata " , " Memory is allocated but not initialized: " + varname ) ;
2010-10-31 12:31:11 +01:00
}
void CheckUninitVar : : uninitvarError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " uninitvar " , " Uninitialized variable: " + varname ) ;
}
2013-01-17 21:04:22 +01:00
void CheckUninitVar : : uninitStructMemberError ( const Token * tok , const std : : string & membername )
{
reportError ( tok ,
2013-01-17 23:18:37 +01:00
Severity : : error ,
2013-01-17 21:04:22 +01:00
" uninitStructMember " ,
2013-01-17 23:18:37 +01:00
" Uninitialized struct member: " + membername ) ;
2013-01-17 21:04:22 +01:00
}