2010-10-31 12:31:11 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2015-01-03 12:14:58 +01:00
* Copyright ( C ) 2007 - 2015 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"
2015-08-03 09:20:50 +02:00
# include "astutils.h"
2010-10-31 12:31:11 +01:00
# include "mathlib.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>
2014-04-21 12:01:02 +02:00
# include <stack>
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
}
//---------------------------------------------------------------------------
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-03-05 13:33:38 +01:00
if ( ( _tokenizer - > isCPP ( ) & & i - > type ( ) & & ! i - > isPointer ( ) & & i - > type ( ) - > needInitialization ! = Type : : True ) | |
2015-07-23 14:51:38 +02:00
i - > isStatic ( ) | | i - > isExtern ( ) | | i - > isReference ( ) )
2012-05-25 13:40:18 +02:00
continue ;
2015-01-21 12:20:03 +01:00
2013-12-24 07:39:15 +01:00
// don't warn for try/catch exception variable
2015-01-21 12:20:03 +01:00
if ( i - > isThrow ( ) )
continue ;
2014-08-05 16:11:42 +02:00
if ( i - > nameToken ( ) - > strAt ( 1 ) = = " ( " | | i - > nameToken ( ) - > strAt ( 1 ) = = " { " )
2012-05-25 13:40:18 +02:00
continue ;
2015-01-21 12:20:03 +01:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( i - > nameToken ( ) , " %name% = " ) ) { // Variable is initialized, but Rhs might be not
2015-07-23 08:46:59 +02:00
checkRhs ( i - > nameToken ( ) , * i , NO_ALLOC , 0U , " " ) ;
2015-01-21 12:20:03 +01:00
continue ;
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( i - > nameToken ( ) , " %name% ) ( " ) & & Token : : simpleMatch ( i - > nameToken ( ) - > linkAt ( 2 ) , " ) = " ) ) { // Function pointer is initialized, but Rhs might be not
2015-07-23 08:46:59 +02:00
checkRhs ( i - > nameToken ( ) - > linkAt ( 2 ) - > next ( ) , * i , NO_ALLOC , 0U , " " ) ;
2015-01-30 19:16:25 +01:00
continue ;
}
2015-01-21 12:20:03 +01:00
2015-08-25 21:19:19 +02:00
if ( i - > isArray ( ) | | i - > isPointerToArray ( ) ) {
2015-07-23 14:51:38 +02:00
const Token * tok = i - > nameToken ( ) - > next ( ) ;
2015-08-25 21:19:19 +02:00
if ( i - > isPointerToArray ( ) )
tok = tok - > next ( ) ;
2015-07-23 14:51:38 +02:00
while ( Token : : simpleMatch ( tok - > link ( ) , " ] [ " ) )
tok = tok - > link ( ) - > next ( ) ;
if ( Token : : simpleMatch ( tok - > link ( ) , " ] = " ) )
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 ( ) ;
2015-08-08 08:53:08 +02:00
for ( ; tok ! = i - > nameToken ( ) & & 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
}
2015-07-23 14:51:38 +02:00
if ( i - > isArray ( ) & & ! stdtype )
continue ;
2015-01-21 12:20:03 +01:00
2012-06-22 16:26:43 +02:00
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
2013-12-12 12:36:49 +01:00
if ( ! tok )
continue ;
2015-01-21 12:20:03 +01:00
2015-07-23 14:51:38 +02:00
if ( i - > isArray ( ) ) {
Alloc alloc = ARRAY ;
checkScopeForVariable ( tok , * i , nullptr , nullptr , & alloc , " " ) ;
continue ;
}
2013-12-04 20:32:20 +01:00
if ( stdtype | | i - > isPointer ( ) ) {
2015-01-23 19:38:39 +01:00
Alloc alloc = NO_ALLOC ;
2015-01-22 13:51:43 +01:00
checkScopeForVariable ( tok , * i , nullptr , nullptr , & alloc , " " ) ;
2013-12-04 20:32:20 +01:00
}
2015-01-21 12:20:03 +01:00
if ( i - > type ( ) )
2015-01-22 13:51:43 +01:00
checkStruct ( tok , * i ) ;
2013-12-09 15:58:42 +01:00
}
2013-09-30 06:35:31 +02:00
2013-12-09 15:58:42 +01:00
if ( scope - > function ) {
for ( unsigned int i = 0 ; i < scope - > function - > argCount ( ) ; i + + ) {
const Variable * arg = scope - > function - > getArgumentVar ( i ) ;
2015-01-31 10:50:39 +01:00
if ( arg & & arg - > declarationId ( ) & & Token : : Match ( arg - > typeStartToken ( ) , " struct| %type% * %name% [,)] " ) ) {
2013-12-09 15:58:42 +01:00
// Treat the pointer as initialized until it is assigned by malloc
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " [;{}] %varid% = %name% ( " , arg - > declarationId ( ) ) & &
2013-12-09 15:58:42 +01:00
_settings - > library . returnuninitdata . count ( tok - > strAt ( 3 ) ) = = 1U ) {
if ( arg - > typeStartToken ( ) - > str ( ) = = " struct " )
2015-01-22 13:51:43 +01:00
checkStruct ( tok , * arg ) ;
2013-12-09 15:58:42 +01:00
else if ( arg - > typeStartToken ( ) - > isStandardType ( ) ) {
2015-01-23 19:38:39 +01:00
Alloc alloc = NO_ALLOC ;
2015-01-22 13:51:43 +01:00
checkScopeForVariable ( tok - > next ( ) , * arg , nullptr , nullptr , & alloc , " " ) ;
2013-12-09 15:58:42 +01:00
}
}
}
}
}
}
}
2013-09-30 06:35:31 +02:00
2015-01-22 13:51:43 +01:00
void CheckUninitVar : : checkStruct ( const Token * tok , const Variable & structvar )
2013-12-09 15:58:42 +01:00
{
const Token * typeToken = structvar . typeStartToken ( ) ;
if ( typeToken - > str ( ) = = " struct " )
typeToken = typeToken - > next ( ) ;
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
for ( std : : size_t j = 0U ; j < symbolDatabase - > classAndStructScopes . size ( ) ; + + j ) {
const Scope * scope2 = symbolDatabase - > classAndStructScopes [ j ] ;
2015-01-23 19:38:39 +01:00
if ( scope2 - > className = = typeToken - > str ( ) & & scope2 - > numConstructors = = 0U ) {
2013-12-09 15:58:42 +01:00
for ( std : : list < Variable > : : const_iterator it = scope2 - > varlist . begin ( ) ; it ! = scope2 - > varlist . end ( ) ; + + it ) {
const Variable & var = * it ;
2015-01-21 13:10:38 +01:00
if ( var . hasDefault ( ) | | var . isArray ( ) | | ( ! _tokenizer - > isC ( ) & & var . isClass ( ) & & ( ! var . type ( ) | | var . type ( ) - > needInitialization ! = Type : : True ) ) )
continue ;
// is the variable declared in a inner union?
bool innerunion = false ;
for ( std : : list < Scope > : : const_iterator it2 = symbolDatabase - > scopeList . begin ( ) ; it2 ! = symbolDatabase - > scopeList . end ( ) ; + + it2 ) {
const Scope & innerScope = * it2 ;
if ( innerScope . type = = Scope : : eUnion & & innerScope . nestedIn = = scope2 ) {
if ( var . typeStartToken ( ) - > linenr ( ) > = innerScope . classStart - > linenr ( ) & &
var . typeStartToken ( ) - > linenr ( ) < = innerScope . classEnd - > linenr ( ) ) {
innerunion = true ;
break ;
2013-09-30 06:35:31 +02:00
}
2013-12-09 15:58:42 +01:00
}
2013-01-16 20:28:29 +01:00
}
2015-01-21 13:10:38 +01:00
if ( ! innerunion ) {
2015-01-23 19:38:39 +01:00
Alloc alloc = NO_ALLOC ;
2015-01-21 13:10:38 +01:00
const Token * tok2 = tok ;
if ( tok - > str ( ) = = " } " )
tok2 = tok2 - > next ( ) ;
2015-01-22 13:51:43 +01:00
checkScopeForVariable ( tok2 , structvar , nullptr , nullptr , & alloc , var . name ( ) ) ;
2015-01-21 13:10:38 +01:00
}
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 ( ) ;
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( vartok , " %name% . %name% " ) )
2013-01-25 18:20:57 +01:00
vartok = vartok - > tokAt ( 2 ) ;
std : : map < unsigned int , int > : : const_iterator it = variableValue . find ( vartok - > varId ( ) ) ;
if ( it = = variableValue . end ( ) )
return ;
// always true
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok , " %name% %oror%|) " ) ) {
2013-01-25 18:20:57 +01:00
if ( NOT )
* alwaysTrue = bool ( it - > second = = 0 ) ;
else
* alwaysTrue = bool ( it - > second ! = 0 ) ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( vartok , " %name% == %num% %or%|) " )) {
2013-01-25 18:20:57 +01:00
* alwaysTrue = bool ( it - > second = = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( vartok , " %name% != %num% %or%|) " )) {
2013-01-25 18:20:57 +01:00
* alwaysTrue = bool ( it - > second ! = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
}
// always false
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok , " %name% &&|) " ) ) {
2013-01-25 18:20:57 +01:00
if ( NOT )
* alwaysFalse = bool ( it - > second ! = 0 ) ;
2013-02-11 17:05:59 +01:00
else
* alwaysFalse = bool ( it - > second = = 0 ) ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( vartok , " %name% == %num% &&|) " )) {
2013-01-25 18:20:57 +01:00
* alwaysFalse = bool ( it - > second ! = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( vartok , " %name% != %num% &&|) " )) {
2013-01-25 18:20:57 +01:00
* alwaysFalse = bool ( it - > second = = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ) ;
}
}
2015-07-22 20:31:58 +02:00
static bool isVariableUsed ( const Token * tok , const Variable & var )
{
if ( ! tok )
return false ;
if ( tok - > str ( ) = = " & " & & ! tok - > astOperand2 ( ) )
return false ;
2015-07-22 22:17:12 +02:00
if ( tok - > isConstOp ( ) )
2015-07-22 20:31:58 +02:00
return isVariableUsed ( tok - > astOperand1 ( ) , var ) | | isVariableUsed ( tok - > astOperand2 ( ) , var ) ;
2015-08-29 13:19:28 +02:00
if ( tok - > varId ( ) ! = var . declarationId ( ) )
return false ;
if ( ! var . isArray ( ) )
return true ;
const Token * parent = tok - > astParent ( ) ;
while ( Token : : Match ( parent , " [?:] " ) )
parent = parent - > astParent ( ) ;
// no dereference, then array is not "used"
if ( ! Token : : Match ( parent , " *|[ " ) )
return false ;
const Token * parent2 = parent - > astParent ( ) ;
// TODO: handle function calls. There is a TODO assertion in TestUninitVar::uninitvar_arrays
return ! parent2 | | parent2 - > isConstOp ( ) | | ( parent2 - > str ( ) = = " = " & & parent2 - > astOperand2 ( ) = = parent ) ;
2015-07-22 20:31:58 +02:00
}
2015-01-23 19:38:39 +01:00
bool CheckUninitVar : : checkScopeForVariable ( const Token * tok , const Variable & var , bool * const possibleInit , bool * const noreturn , Alloc * const alloc , 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 ) ;
2015-04-10 14:18:52 +02:00
const bool printDebug = _settings - > debugwarnings ;
2011-12-26 12:36:35 +01:00
if ( possibleInit )
* possibleInit = false ;
2011-12-13 21:57:27 +01:00
unsigned int number_of_if = 0 ;
2013-12-04 20:32:20 +01:00
if ( var . declarationId ( ) = = 0U )
return true ;
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 ;
2015-03-14 17:59:11 +01:00
return false ;
2013-01-28 18:08:20 +01:00
}
2011-12-13 21:57:27 +01:00
break ;
}
2015-01-22 13:51:43 +01:00
// Unconditional inner scope or try..
if ( tok - > str ( ) = = " { " & & Token : : Match ( tok - > previous ( ) , " ;|{|}|try " ) ) {
if ( checkScopeForVariable ( tok - > next ( ) , var , possibleInit , noreturn , alloc , 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..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [;{}] %var% = - %name% ; " ) )
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..
2015-01-22 13:51:43 +01:00
else 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..
2015-01-23 19:38:39 +01:00
if ( ! alwaysTrue & & checkIfForWhileHead ( tok - > next ( ) , var , suppressErrors , bool ( number_of_if = = 0 ) , * alloc , 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 ;
2015-07-25 17:55:01 +02:00
const Token * condVarTok = nullptr ;
if ( Token : : simpleMatch ( tok , " if ( " ) & &
2015-08-03 09:20:50 +02:00
astIsVariableComparison ( tok - > next ( ) - > astOperand2 ( ) , " != " , " 0 " , & condVarTok ) ) {
2015-07-25 17:55:01 +02:00
std : : map < unsigned int , int > : : const_iterator it = variableValue . find ( condVarTok - > varId ( ) ) ;
2012-12-24 19:11:13 +01:00
if ( it ! = variableValue . end ( ) & & it - > second = = NOT_ZERO )
return true ; // this scope is not fully analysed => return true
else {
2015-07-25 17:55:01 +02:00
condVarId = condVarTok - > varId ( ) ;
2012-12-24 19:11:13 +01:00
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 ;
2015-01-22 13:51:43 +01:00
const bool initif = ! alwaysFalse & & checkScopeForVariable ( tok - > next ( ) , var , & possibleInitIf , & noreturnIf , alloc , 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 ) {
2015-04-10 14:18:52 +02:00
if ( printDebug ) {
2012-12-28 11:42:50 +01:00
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 + = ' ' ;
}
2014-08-26 11:29:26 +02:00
reportError ( tok , Severity : : debug , " debug " , " bailout uninitialized variable checking for ' " + var . name ( ) + " '. can't determine if this condition can be false when previous condition is false: " + condition ) ;
2012-12-28 11:42:50 +01:00
}
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
2013-04-08 19:34:39 +02:00
if ( alwaysTrue & & noreturnIf )
return true ;
2012-12-24 19:11:13 +01:00
std : : map < unsigned int , int > varValueIf ;
2013-05-06 18:45:00 +02:00
if ( ! alwaysFalse & & ! initif & & ! noreturnIf ) {
2012-12-23 16:27:04 +01:00
for ( const Token * tok2 = tok ; tok2 & & tok2 ! = tok - > link ( ) ; tok2 = tok2 - > next ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %name% = - %name% ; " ) )
2012-12-24 19:11:13 +01:00
varValueIf [ tok2 - > next ( ) - > varId ( ) ] = NOT_ZERO ;
2015-03-14 13:09:46 +01:00
else if ( Token : : Match ( tok2 , " [;{}.] %name% = %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 ;
2015-04-08 15:35:04 +02:00
const bool initelse = ! alwaysTrue & & checkScopeForVariable ( tok - > next ( ) , var , & possibleInitElse , & noreturnElse , alloc , membervar ) ;
2011-12-13 21:57:27 +01:00
2012-12-24 19:11:13 +01:00
std : : map < unsigned int , int > varValueElse ;
2013-05-06 18:45:00 +02:00
if ( ! alwaysTrue & & ! initelse & & ! noreturnElse ) {
2012-12-23 16:27:04 +01:00
for ( const Token * tok2 = tok ; tok2 & & tok2 ! = tok - > link ( ) ; tok2 = tok2 - > next ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok2 , " [;{}.] %var% = - %name% ; " ) )
2012-12-24 19:11:13 +01:00
varValueElse [ tok2 - > next ( ) - > varId ( ) ] = NOT_ZERO ;
2015-02-03 13:01:09 +01:00
else 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
}
}
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
2013-05-06 18:45:00 +02:00
if ( ( alwaysFalse | | initif | | noreturnIf ) & &
( alwaysTrue | | initelse | | noreturnElse ) )
2012-11-29 18:41:48 +01:00
return true ;
2015-04-08 15:35:04 +02:00
if ( initif | | initelse | | possibleInitElse )
2012-01-13 23:30:43 +01:00
+ + number_of_if ;
2015-04-08 15:35:04 +02:00
if ( ! initif & & ! noreturnIf )
2012-12-24 19:11:13 +01:00
variableValue . insert ( varValueIf . begin ( ) , varValueIf . end ( ) ) ;
2015-04-08 15:35:04 +02:00
if ( ! initelse & & ! noreturnElse )
2012-12-24 19:11:13 +01:00
variableValue . insert ( varValueElse . begin ( ) , varValueElse . end ( ) ) ;
2012-01-13 23:30:43 +01:00
}
2011-12-13 21:57:27 +01:00
}
}
2011-12-17 07:56:46 +01:00
// = { .. }
2015-01-22 13:51:43 +01:00
else if ( Token : : simpleMatch ( tok , " = { " ) ) {
2011-12-17 07:56:46 +01:00
// end token
const Token * end = tok - > next ( ) - > link ( ) ;
// If address of variable is taken in the block then bail out
2013-07-20 12:31:04 +02:00
if ( Token : : findmatch ( tok - > tokAt ( 2 ) , " & %varid% " , end , var . declarationId ( ) ) )
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..
2015-01-22 13:51:43 +01:00
else if ( Token : : Match ( tok , " for|while ( " ) | | Token : : simpleMatch ( tok , " do { " )) {
2013-06-25 18:40:41 +02:00
const bool forwhile = Token : : Match ( tok , " for|while ( " ) ;
2011-12-27 08:18:05 +01:00
// is variable initialized in for-head (don't report errors yet)?
2015-01-23 19:38:39 +01:00
if ( forwhile & & checkIfForWhileHead ( tok - > next ( ) , var , true , false , * alloc , membervar ) )
2011-12-27 08:18:05 +01:00
return true ;
2011-12-26 18:32:42 +01:00
// goto the {
2013-06-25 18:40:41 +02:00
const Token * tok2 = forwhile ? tok - > next ( ) - > link ( ) - > next ( ) : tok - > next ( ) ;
2011-12-26 18:32:42 +01:00
2012-01-13 23:30:43 +01:00
if ( tok2 & & tok2 - > str ( ) = = " { " ) {
2015-01-23 19:38:39 +01:00
bool init = checkLoopBody ( tok2 , var , * alloc , membervar , ( number_of_if > 0 ) | | suppressErrors ) ;
2011-12-26 18:32:42 +01:00
2012-01-13 23:30:43 +01:00
// variable is initialized in the loop..
2013-05-29 16:16:12 +02:00
if ( init )
2012-01-13 23:30:43 +01:00
return true ;
2011-12-26 18:32:42 +01:00
2012-01-13 23:30:43 +01:00
// is variable used in for-head?
2013-12-13 13:27:01 +01:00
bool initcond = false ;
2012-01-13 23:30:43 +01:00
if ( ! suppressErrors ) {
2013-06-25 18:40:41 +02:00
const Token * startCond = forwhile ? tok - > next ( ) : tok - > next ( ) - > link ( ) - > tokAt ( 2 ) ;
2015-01-23 19:38:39 +01:00
initcond = checkIfForWhileHead ( startCond , var , false , bool ( number_of_if = = 0 ) , * alloc , membervar ) ;
2012-01-13 23:30:43 +01:00
}
2012-11-29 18:41:48 +01:00
// goto "}"
tok = tok2 - > link ( ) ;
2013-06-25 18:40:41 +02:00
// do-while => goto ")"
2013-07-28 12:41:38 +02:00
if ( ! forwhile ) {
// Assert that the tokens are '} while ('
2013-11-06 17:53:09 +01:00
if ( ! Token : : simpleMatch ( tok , " } while ( " ) ) {
2015-04-10 14:18:52 +02:00
if ( printDebug )
2013-11-06 17:53:09 +01:00
reportError ( tok , Severity : : debug , " " , " assertion failed '} while (' " ) ;
break ;
}
2013-07-28 12:41:38 +02:00
// Goto ')'
2013-06-25 18:40:41 +02:00
tok = tok - > linkAt ( 2 ) ;
2013-07-28 12:41:38 +02:00
if ( ! tok )
// bailout : invalid code / bad tokenizer
break ;
2013-12-13 13:27:01 +01:00
if ( initcond )
// variable is initialized in while-condition
return true ;
2013-07-28 12:41:38 +02:00
}
2011-12-27 08:18:05 +01:00
}
2011-12-26 18:32:42 +01:00
}
2015-01-22 13:51:43 +01:00
// Unknown or unhandled inner scope
2015-01-31 10:50:39 +01:00
else if ( Token : : simpleMatch ( tok , " ) { " ) || (Token::Match(tok, " % name % { " ) && tok->str() != " try " )) {
2015-01-22 13:51:43 +01:00
if ( tok - > str ( ) = = " struct " | | tok - > str ( ) = = " union " ) {
tok = tok - > linkAt ( 1 ) ;
continue ;
}
2011-12-15 20:29:57 +01:00
return true ;
}
2015-01-06 07:44:04 +01:00
// bailout if there is ({
if ( Token : : simpleMatch ( tok , " ( { " ) ) {
return true ;
}
2015-01-21 16:49:34 +01:00
// bailout if there is assembler code or setjmp
if ( Token : : Match ( tok , " asm|setjmp ( " ) ) {
2011-12-15 20:29:57 +01:00
return true ;
2011-12-14 18:54:03 +01:00
}
2015-01-21 22:26:44 +01:00
if ( tok - > str ( ) = = " ? " ) {
2015-07-22 22:17:12 +02:00
if ( ! tok - > astOperand2 ( ) )
return true ;
2015-07-22 20:31:58 +02:00
const bool used1 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand1 ( ) , var ) ;
const bool used0 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand2 ( ) , var ) ;
const bool err = ( number_of_if = = 0 ) ? ( used1 | | used0 ) : ( used1 & & used0 ) ;
2015-07-23 08:46:59 +02:00
if ( err )
uninitvarError ( tok , var . nameToken ( ) - > str ( ) , * alloc ) ;
2015-07-22 20:31:58 +02:00
// Todo: skip expression if there is no error
2015-01-21 22:02:25 +01:00
return true ;
}
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
2015-08-16 14:22:46 +02:00
tok = tok - > next ( ) ;
2012-12-25 10:37:21 +01:00
while ( tok & & tok - > str ( ) ! = " ; " ) {
// variable is seen..
2013-07-20 12:31:04 +02:00
if ( tok - > varId ( ) = = var . declarationId ( ) ) {
2013-01-20 17:54:32 +01:00
if ( ! membervar . empty ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% . %name% ;|%cop% " ) & & tok - > strAt ( 2 ) = = membervar )
2013-01-20 17:54:32 +01:00
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
else
return true ;
}
2012-12-25 10:37:21 +01:00
// Use variable
2015-07-23 09:21:53 +02:00
else if ( ! suppressErrors & & isVariableUsage ( tok , var . isPointer ( ) , * alloc ) )
2015-07-23 08:46:59 +02:00
uninitvarError ( tok , tok - > str ( ) , * alloc ) ;
2014-12-18 06:37:15 +01:00
else
2012-12-25 10:37:21 +01:00
// 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 ) ;
2015-07-22 20:31:58 +02:00
else if ( tok - > str ( ) = = " ? " ) {
2015-07-22 22:17:12 +02:00
if ( ! tok - > astOperand2 ( ) )
return true ;
2015-07-22 20:31:58 +02:00
const bool used1 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand1 ( ) , var ) ;
const bool used0 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand2 ( ) , var ) ;
const bool err = ( number_of_if = = 0 ) ? ( used1 | | used0 ) : ( used1 & & used0 ) ;
2015-07-23 08:46:59 +02:00
if ( err )
uninitvarError ( tok , var . nameToken ( ) - > str ( ) , * alloc ) ;
2013-07-10 16:44:35 +02:00
return true ;
2015-07-22 20:31:58 +02:00
}
2013-07-10 16:44:35 +02:00
2012-12-25 10:37:21 +01:00
tok = tok - > next ( ) ;
}
2014-02-15 08:46:28 +01:00
return bool ( noreturn = = nullptr ) ;
2012-12-25 10:37:21 +01:00
}
2011-12-13 21:57:27 +01:00
// variable is seen..
2013-07-20 12:31:04 +02:00
if ( tok - > varId ( ) = = var . declarationId ( ) ) {
2013-12-04 20:32:20 +01:00
// calling function that returns uninit data through pointer..
if ( var . isPointer ( ) & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tok - > next ( ) , " = %name% ( " ) & &
2013-12-04 20:32:20 +01:00
Token : : simpleMatch ( tok - > linkAt ( 3 ) , " ) ; " ) & &
_settings - > library . returnuninitdata . count ( tok - > strAt ( 2 ) ) > 0U ) {
2015-02-17 19:32:59 +01:00
* alloc = NO_CTOR_CALL ;
2013-12-04 20:32:20 +01:00
continue ;
}
2015-01-22 10:53:01 +01:00
if ( var . isPointer ( ) & & ( var . typeStartToken ( ) - > isStandardType ( ) | | ( var . type ( ) & & var . type ( ) - > needInitialization = = Type : : True ) ) & & Token : : simpleMatch ( tok - > next ( ) , " = new " ) ) {
2015-02-17 19:32:59 +01:00
* alloc = CTOR_CALL ;
if ( var . typeScope ( ) & & var . typeScope ( ) - > numConstructors > 0 )
return true ;
2015-01-21 23:46:52 +01:00
continue ;
}
2013-12-04 20:32:20 +01:00
2013-01-19 12:48:56 +01:00
if ( ! membervar . empty ( ) ) {
2013-06-27 16:53:15 +02:00
if ( isMemberVariableAssignment ( tok , membervar ) ) {
2015-07-23 08:46:59 +02:00
checkRhs ( tok , var , * alloc , number_of_if , membervar ) ;
2013-01-17 17:21:21 +01:00
return true ;
2013-06-27 16:53:15 +02:00
}
2013-01-24 19:41:15 +01:00
2015-01-23 19:38:39 +01:00
if ( isMemberVariableUsage ( tok , var . isPointer ( ) , * alloc , membervar ) )
2013-01-19 12:48:56 +01:00
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
2013-01-24 19:41:15 +01:00
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok - > previous ( ) , " [(,] %name% [,)] " ) )
2013-04-10 20:04:32 +02:00
return true ;
2013-01-16 20:28:29 +01:00
} else {
// Use variable
2015-07-23 09:21:53 +02:00
if ( ! suppressErrors & & isVariableUsage ( tok , var . isPointer ( ) , * alloc ) )
2015-07-23 08:46:59 +02:00
uninitvarError ( tok , tok - > str ( ) , * alloc ) ;
2011-12-14 06:00:17 +01:00
2013-06-27 16:53:15 +02:00
else {
2013-06-29 09:33:51 +02:00
if ( tok - > strAt ( 1 ) = = " = " )
2015-07-23 08:46:59 +02:00
checkRhs ( tok , var , * alloc , number_of_if , " " ) ;
2013-06-27 16:53:15 +02:00
2013-01-16 20:28:29 +01:00
// assume that variable is assigned
return true ;
2013-06-27 16:53:15 +02:00
}
2013-01-16 20:28:29 +01:00
}
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
}
2015-01-23 19:38:39 +01:00
bool CheckUninitVar : : checkIfForWhileHead ( const Token * startparentheses , const Variable & var , bool suppressErrors , bool isuninit , Alloc alloc , 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 ( ) ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( startparentheses , " ( ! %name% %oror% " ) & & startparentheses - > tokAt ( 2 ) - > getValue ( 0 ) )
2014-11-01 14:03:02 +01:00
suppressErrors = true ;
2013-01-16 15:37:07 +01:00
for ( const Token * tok = startparentheses - > next ( ) ; tok & & tok ! = endpar ; tok = tok - > next ( ) ) {
2013-07-20 12:31:04 +02:00
if ( tok - > varId ( ) = = var . declarationId ( ) ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% . %name% " ) ) {
2013-02-05 17:01:46 +01:00
if ( tok - > strAt ( 2 ) = = membervar ) {
2013-02-23 15:57:58 +01:00
if ( isMemberVariableAssignment ( tok , membervar ) )
2013-02-05 17:01:46 +01:00
return true ;
2013-02-23 15:57:58 +01:00
2013-12-04 20:32:20 +01:00
if ( ! suppressErrors & & isMemberVariableUsage ( tok , var . isPointer ( ) , alloc , membervar ) )
2013-02-05 17:01:46 +01:00
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
}
2013-01-19 12:48:56 +01:00
continue ;
}
2015-01-21 13:52:03 +01:00
if ( isVariableUsage ( tok , var . isPointer ( ) , alloc ) ) {
2015-03-20 09:03:11 +01:00
if ( suppressErrors )
2011-12-27 08:18:05 +01:00
continue ;
2015-07-23 08:46:59 +02:00
uninitvarError ( tok , tok - > str ( ) , alloc ) ;
2011-12-27 08:18:05 +01:00
}
2011-12-26 18:32:42 +01:00
return true ;
}
if ( Token : : Match ( tok , " sizeof|decltype|offsetof ( " ) )
tok = tok - > next ( ) - > link ( ) ;
2013-12-04 20:32:20 +01:00
if ( ( ! isuninit | | ! membervar . empty ( ) ) & & tok - > str ( ) = = " && " )
2011-12-26 18:32:42 +01:00
suppressErrors = true ;
}
return false ;
}
2015-01-23 19:38:39 +01:00
bool CheckUninitVar : : checkLoopBody ( const Token * tok , const Variable & var , const Alloc alloc , const std : : string & membervar , const bool suppressErrors )
2013-01-24 19:41:15 +01:00
{
2014-02-15 08:46:28 +01:00
const Token * usetok = nullptr ;
2013-01-24 19:41:15 +01:00
assert ( tok - > str ( ) = = " { " ) ;
for ( const Token * const end = tok - > link ( ) ; tok ! = end ; tok = tok - > next ( ) ) {
2013-07-20 12:31:04 +02:00
if ( tok - > varId ( ) = = var . declarationId ( ) ) {
2013-01-24 19:41:15 +01:00
if ( ! membervar . empty ( ) ) {
2013-06-25 18:40:41 +02:00
if ( isMemberVariableAssignment ( tok , membervar ) ) {
bool assign = true ;
bool rhs = false ;
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " = " )
rhs = true ;
if ( tok2 - > str ( ) = = " ; " )
break ;
2013-12-04 20:32:20 +01:00
if ( rhs & & tok2 - > varId ( ) = = var . declarationId ( ) & & isMemberVariableUsage ( tok2 , var . isPointer ( ) , alloc , membervar ) ) {
2013-06-25 18:40:41 +02:00
assign = false ;
break ;
}
}
if ( assign )
return true ;
}
2013-01-24 19:41:15 +01:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% = " ) )
2013-12-04 20:32:20 +01:00
return true ;
if ( isMemberVariableUsage ( tok , var . isPointer ( ) , alloc , membervar ) )
2013-01-24 19:41:15 +01:00
usetok = tok ;
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok - > previous ( ) , " [(,] %name% [,)] " ) )
2013-04-10 20:46:44 +02:00
return true ;
2013-01-24 19:41:15 +01:00
} else {
2015-01-21 13:52:03 +01:00
if ( isVariableUsage ( tok , var . isPointer ( ) , alloc ) )
2013-01-24 19:41:15 +01:00
usetok = tok ;
2014-04-21 12:01:02 +02:00
else if ( tok - > strAt ( 1 ) = = " = " ) {
// Is var used in rhs?
bool rhs = false ;
std : : stack < const Token * > tokens ;
tokens . push ( tok - > next ( ) - > astOperand2 ( ) ) ;
while ( ! tokens . empty ( ) ) {
const Token * t = tokens . top ( ) ;
tokens . pop ( ) ;
if ( ! t )
continue ;
if ( t - > varId ( ) = = var . declarationId ( ) ) {
// var is used in rhs
rhs = true ;
break ;
2013-06-25 18:40:41 +02:00
}
2014-04-21 12:01:02 +02:00
if ( Token : : simpleMatch ( t - > previous ( ) , " sizeof ( " ) )
continue ;
tokens . push ( t - > astOperand1 ( ) ) ;
tokens . push ( t - > astOperand2 ( ) ) ;
2013-06-25 18:40:41 +02:00
}
2014-04-21 12:01:02 +02:00
if ( ! rhs )
2013-06-25 18:40:41 +02:00
return true ;
2014-04-21 12:01:02 +02:00
} else {
return true ;
2013-06-25 18:40:41 +02:00
}
2013-01-24 19:41:15 +01:00
}
}
2013-02-12 15:59:23 +01:00
2013-03-22 08:10:46 +01:00
if ( Token : : Match ( tok , " sizeof|typeof ( " ) )
tok = tok - > next ( ) - > link ( ) ;
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 ( ) )
2015-07-23 08:46:59 +02:00
uninitvarError ( usetok , usetok - > str ( ) , alloc ) ;
2013-01-24 19:41:15 +01:00
else
uninitStructMemberError ( usetok , usetok - > str ( ) + " . " + membervar ) ;
return true ;
}
return false ;
}
2015-07-23 08:46:59 +02:00
void CheckUninitVar : : checkRhs ( const Token * tok , const Variable & var , Alloc alloc , unsigned int number_of_if , const std : : string & membervar )
2013-06-29 09:33:51 +02:00
{
bool rhs = false ;
unsigned int indent = 0 ;
2014-02-15 08:46:28 +01:00
while ( nullptr ! = ( tok = tok - > next ( ) ) ) {
2013-06-29 09:33:51 +02:00
if ( tok - > str ( ) = = " = " )
rhs = true ;
2013-07-20 12:31:04 +02:00
else if ( rhs & & tok - > varId ( ) = = var . declarationId ( ) ) {
2015-01-21 13:52:03 +01:00
if ( membervar . empty ( ) & & isVariableUsage ( tok , var . isPointer ( ) , alloc ) )
2015-07-23 08:46:59 +02:00
uninitvarError ( tok , tok - > str ( ) , alloc ) ;
2013-12-04 20:32:20 +01:00
else if ( ! membervar . empty ( ) & & isMemberVariableUsage ( tok , var . isPointer ( ) , alloc , membervar ) )
2013-06-29 09:33:51 +02:00
uninitStructMemberError ( tok , tok - > str ( ) + " . " + membervar ) ;
} else if ( tok - > str ( ) = = " ; " || (indent==0 && tok->str() == " , " ))
break ;
else if ( tok - > str ( ) = = " ( " )
+ + indent ;
else if ( tok - > str ( ) = = " ) " ) {
if ( indent = = 0 )
break ;
- - indent ;
2015-07-23 08:46:59 +02:00
} else if ( tok - > str ( ) = = " ? " & & tok - > astOperand2 ( ) ) {
const bool used1 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand1 ( ) , var ) ;
const bool used0 = isVariableUsed ( tok - > astOperand2 ( ) - > astOperand2 ( ) , var ) ;
const bool err = ( number_of_if = = 0 ) ? ( used1 | | used0 ) : ( used1 & & used0 ) ;
if ( err )
uninitvarError ( tok , var . nameToken ( ) - > str ( ) , alloc ) ;
break ;
2013-07-06 08:52:47 +02:00
} else if ( Token : : simpleMatch ( tok , " sizeof ( " ) )
2013-07-07 10:26:20 +02:00
tok = tok - > next ( ) - > link ( ) ;
2013-06-29 09:33:51 +02:00
}
}
2015-01-23 19:38:39 +01:00
bool CheckUninitVar : : isVariableUsage ( const Token * vartok , bool pointer , Alloc alloc ) const
2011-12-14 18:28:30 +01:00
{
2015-01-23 19:38:39 +01:00
if ( alloc = = NO_ALLOC & & ( ( Token : : Match ( vartok - > previous ( ) , " return|delete " ) & & vartok - > strAt ( 1 ) ! = " = " ) | | ( vartok - > strAt ( - 1 ) = = " ] " & & vartok - > linkAt ( - 1 ) - > strAt ( - 1 ) = = " delete " ) ) )
2011-12-14 18:28:30 +01:00
return true ;
2014-12-20 18:47:40 +01:00
// Passing variable to typeof/__alignof__
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok - > tokAt ( - 3 ) , " typeof|__alignof__ ( * %name% " ) )
2013-10-12 18:46:14 +02:00
return false ;
2014-09-14 10:29:12 +02:00
// Accessing Rvalue member using "." or "->"
2014-09-12 08:19:00 +02:00
if ( vartok - > strAt ( 1 ) = = " . " & & vartok - > strAt ( - 1 ) ! = " & " ) {
2014-09-15 15:58:21 +02:00
// Is struct member passed to function?
2015-01-31 10:50:39 +01:00
if ( ! pointer & & Token : : Match ( vartok - > previous ( ) , " [,(] %name% . %name% " ) ) {
2014-09-15 15:58:21 +02:00
// TODO: there are FN currently:
// - should only return false if struct member is (or might be) array.
// - should only return false if function argument is (or might be) non-const pointer or reference
const Token * tok2 = vartok - > next ( ) ;
2015-05-13 13:40:40 +02:00
do {
2014-09-15 15:58:21 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2015-05-13 13:40:40 +02:00
} while ( Token : : Match ( tok2 , " . %name% " ) ) ;
2014-09-15 15:58:21 +02:00
if ( Token : : Match ( tok2 , " [,)] " ) )
return false ;
2015-01-31 10:50:39 +01:00
} else if ( pointer & & alloc ! = CTOR_CALL & & Token : : Match ( vartok , " %name% . %name% ( " ) ) {
2015-01-21 16:17:58 +01:00
return true ;
2014-09-15 15:58:21 +02:00
}
2015-01-21 16:17:58 +01:00
2014-09-12 08:19:00 +02:00
bool assignment = false ;
const Token * parent = vartok - > astParent ( ) ;
while ( parent ) {
if ( parent - > str ( ) = = " = " ) {
assignment = true ;
break ;
}
2015-01-23 19:38:39 +01:00
if ( alloc ! = NO_ALLOC & & parent - > str ( ) = = " ( " ) {
2015-01-21 22:26:44 +01:00
if ( _settings - > library . functionpure . find ( parent - > strAt ( - 1 ) ) = = _settings - > library . functionpure . end ( ) ) {
assignment = true ;
break ;
}
}
2014-09-12 08:19:00 +02:00
parent = parent - > astParent ( ) ;
}
2014-09-14 10:29:12 +02:00
if ( ! assignment )
2014-09-12 08:19:00 +02:00
return true ;
}
2012-12-20 19:45:30 +01:00
// Passing variable to function..
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok - > previous ( ) , " [(,] %name% [,)] " ) | | Token : : Match ( vartok - > tokAt ( - 2 ) , " [(,] & %name% [,)] " ) ) {
2015-06-20 11:33:27 +02:00
const int use = isFunctionParUsage ( vartok , pointer , alloc ) ;
2015-06-19 18:21:46 +02:00
if ( use > = 0 )
2015-06-28 16:49:16 +02:00
return ( use > 0 ) ;
2012-12-20 19:45:30 +01:00
}
2013-11-17 12:42:53 +01:00
if ( Token : : Match ( vartok - > previous ( ) , " ++|--|%cop% " ) ) {
2015-01-21 16:17:58 +01:00
if ( _tokenizer - > isCPP ( ) & & Token : : Match ( vartok - > previous ( ) , " >>|<< " ) ) {
2015-01-22 22:55:08 +01:00
const Token * tok2 = vartok - > previous ( ) ;
if ( Token : : simpleMatch ( tok2 - > astOperand1 ( ) , " >> " ) )
return false ; // Looks like stream operator, initializes the variable
if ( Token : : simpleMatch ( tok2 , " << " ) ) {
// Looks like stream operator, but could also initialize the variable. Check lhs.
do {
tok2 = tok2 - > astOperand1 ( ) ;
} while ( Token : : simpleMatch ( tok2 , " << " ) ) ;
2015-04-17 08:47:59 +02:00
if ( tok2 & & tok2 - > strAt ( - 1 ) = = " :: " )
2015-01-22 22:55:08 +01:00
tok2 = tok2 - > previous ( ) ;
if ( tok2 & & ( Token : : simpleMatch ( tok2 - > previous ( ) , " std :: " ) | | ( tok2 - > variable ( ) & & tok2 - > variable ( ) - > isStlType ( ) ) | | tok2 - > isStandardType ( ) ) )
return true ;
}
2015-01-21 16:17:58 +01:00
const Variable * var = vartok - > tokAt ( - 2 ) - > variable ( ) ;
return ( var & & var - > typeStartToken ( ) - > isStandardType ( ) ) ;
2011-12-15 16:55:55 +01:00
}
2012-07-03 18:52:23 +02:00
// is there something like: ; "*((&var ..expr.. =" => the variable is assigned
2015-01-04 09:23:24 +01:00
if ( vartok - > previous ( ) - > str ( ) = = " & " & & ! vartok - > previous ( ) - > astOperand2 ( ) )
return false ;
2012-07-03 18:52:23 +02:00
2015-01-04 11:13:20 +01:00
// bailout to avoid fp for 'int x = 2 + x();' where 'x()' is a unseen preprocessor macro (seen in linux)
if ( ! pointer & & vartok - > next ( ) & & vartok - > next ( ) - > str ( ) = = " ( " )
return false ;
2012-01-02 11:25:13 +01:00
if ( vartok - > previous ( ) - > str ( ) ! = " & " | | ! Token : : Match ( vartok - > tokAt ( - 2 ) , " [(,=?:] " ) ) {
2015-01-23 19:38:39 +01:00
if ( alloc ! = NO_ALLOC & & vartok - > previous ( ) - > str ( ) = = " * " ) {
2013-12-12 15:33:31 +01:00
const Token * parent = vartok - > previous ( ) - > astParent ( ) ;
if ( parent & & parent - > str ( ) = = " = " & & parent - > astOperand1 ( ) = = vartok - > previous ( ) )
return false ;
return true ;
}
2015-01-23 19:38:39 +01:00
return alloc = = NO_ALLOC ;
2011-12-14 18:28:30 +01:00
}
}
2015-01-31 10:50:39 +01:00
if ( alloc = = NO_ALLOC & & Token : : Match ( vartok - > previous ( ) , " = %name% ;|%cop% " ) )
2013-11-16 18:07:33 +01:00
return true ;
2011-12-26 14:01:46 +01:00
bool unknown = false ;
2013-12-23 16:50:27 +01:00
if ( pointer & & CheckNullPointer : : isPointerDeRef ( vartok , unknown ) ) {
2013-12-12 11:44:07 +01:00
// pointer is allocated - dereferencing it is ok.
2015-01-23 19:38:39 +01:00
if ( alloc ! = NO_ALLOC )
2013-12-04 20:32:20 +01:00
return false ;
2011-12-27 10:18:49 +01:00
// function parameter?
bool functionParameter = false ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok - > tokAt ( - 2 ) , " %name% ( " ) | | vartok - > previous ( ) - > str ( ) = = " , " )
2011-12-27 10:18:49 +01:00
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
2015-01-21 13:52:03 +01:00
if ( _tokenizer - > isCPP ( ) & & Token : : Match ( vartok - > next ( ) , " <<|>> " ) ) {
2012-12-18 19:02:30 +01:00
// Is this calculation done in rhs?
const Token * tok = vartok ;
2015-01-31 10:50:39 +01:00
while ( tok & & Token : : Match ( tok , " %name%|.|:: " ) )
2012-12-18 19:02:30 +01:00
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
}
2015-01-23 19:38:39 +01:00
if ( alloc = = NO_ALLOC & & vartok - > next ( ) & & vartok - > next ( ) - > isOp ( ) & & ! vartok - > next ( ) - > isAssignmentOp ( ) )
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 ;
}
2015-06-19 18:21:46 +02:00
/***
* Is function parameter " used " so a " usage of uninitialized variable " can
* be written ? If parameter is passed " by value " then it is " used " . If it
* is passed " by reference " then it is not necessarily " used " .
* @ return - 1 = > unknown 0 = > not used 1 = > used
*/
int CheckUninitVar : : isFunctionParUsage ( const Token * vartok , bool pointer , Alloc alloc ) const
{
if ( ! Token : : Match ( vartok - > previous ( ) , " [(,] " ) & & ! Token : : Match ( vartok - > tokAt ( - 2 ) , " [(,] & " ) )
return - 1 ;
// locate start parentheses in function call..
unsigned 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 ( ) , " %name% ( " ) ) {
const bool address ( vartok - > previous ( ) - > str ( ) = = " & " ) ;
2015-08-05 10:19:17 +02:00
const bool array ( vartok - > variable ( ) & & vartok - > variable ( ) - > isArray ( ) ) ;
2015-06-19 18:21:46 +02:00
// check how function handle uninitialized data arguments..
const Function * func = start - > previous ( ) - > function ( ) ;
if ( func ) {
const Variable * arg = func - > getArgumentVar ( argumentNumber ) ;
if ( arg ) {
const Token * argStart = arg - > typeStartToken ( ) ;
2015-08-05 10:19:17 +02:00
if ( ! address & & ! array & & Token : : Match ( argStart , " struct| %type% %name%| [,)] " ) )
2015-06-19 18:21:46 +02:00
return 1 ;
if ( pointer & & ! address & & alloc = = NO_ALLOC & & Token : : Match ( argStart , " struct| %type% * %name% [,)] " ) )
return 1 ;
while ( argStart - > previous ( ) & & argStart - > previous ( ) - > isName ( ) )
argStart = argStart - > previous ( ) ;
if ( Token : : Match ( argStart , " const %type% & %name% [,)] " ) )
return 1 ;
if ( ( pointer | | address ) & & alloc = = NO_ALLOC & & Token : : Match ( argStart , " const struct| %type% * %name% [,)] " ) )
return 1 ;
if ( ( pointer | | address ) & & Token : : Match ( argStart , " const %type% %name% [ " ) & & Token : : Match ( argStart - > linkAt ( 3 ) , " ] [,)] " ) )
return 1 ;
}
} else if ( Token : : Match ( start - > previous ( ) , " if|while|for " ) ) {
// control-flow statement reading the variable "by value"
return alloc = = NO_ALLOC ;
} else {
const bool isnullbad = _settings - > library . isnullargbad ( start - > previous ( ) , argumentNumber + 1 ) ;
2015-07-22 21:58:06 +02:00
if ( pointer & & ! address & & isnullbad & & alloc = = NO_ALLOC )
2015-07-22 20:31:58 +02:00
return true ;
2015-06-19 18:21:46 +02:00
const bool isuninitbad = _settings - > library . isuninitargbad ( start - > previous ( ) , argumentNumber + 1 ) ;
if ( alloc ! = NO_ALLOC )
return isnullbad & & isuninitbad ;
return isuninitbad & & ( ! address | | isnullbad ) ;
}
}
// unknown
return - 1 ;
}
bool CheckUninitVar : : isMemberVariableAssignment ( const Token * tok , const std : : string & membervar ) const
2013-01-24 19:41:15 +01:00
{
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " %name% . %name% " ) & & tok - > strAt ( 2 ) = = membervar ) {
2013-01-24 19:41:15 +01:00
if ( Token : : Match ( tok - > tokAt ( 3 ) , " [=.[] " ) )
return true ;
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " [(,=] & " ) )
return true ;
2015-05-10 14:27:15 +02:00
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %name% >> " ) & & Token : : Match ( tok - > tokAt ( 3 ) , " ; | > > " )) // #6680
return true ;
2013-03-01 11:43:59 +01:00
else if ( ( tok - > previous ( ) & & tok - > previous ( ) - > isConstOp ( ) ) | | Token : : Match ( tok - > previous ( ) , " [|= " ) )
2013-01-24 19:41:15 +01:00
; // member variable usage
2013-05-02 20:34:15 +02:00
else if ( tok - > tokAt ( 3 ) - > isConstOp ( ) )
; // member variable usage
2015-06-19 18:21:46 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " [(,] %name% . %name% [,)] " ) & &
1 = = isFunctionParUsage ( tok , false , NO_ALLOC ) ) {
return false ;
} else
2013-01-24 19:41:15 +01:00
return true ;
} else if ( tok - > strAt ( 1 ) = = " = " )
return true ;
2014-03-20 06:48:17 +01:00
else if ( tok - > strAt ( - 1 ) = = " & " ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " [(,] & %name% " ) ) {
2014-03-20 06:48:17 +01:00
// locate start parentheses in function call..
unsigned int argumentNumber = 0 ;
const Token * ftok = tok ;
while ( ftok & & ! Token : : Match ( ftok , " [;{}(] " ) ) {
if ( ftok - > str ( ) = = " ) " )
ftok = ftok - > link ( ) ;
else if ( ftok - > str ( ) = = " , " )
+ + argumentNumber ;
ftok = ftok - > previous ( ) ;
}
// is this a function call?
ftok = ftok ? ftok - > previous ( ) : NULL ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( ftok , " %name% ( " ) ) {
2014-03-20 06:48:17 +01:00
// check how function handle uninitialized data arguments..
const Function * function = ftok - > function ( ) ;
const Variable * arg = function ? function - > getArgumentVar ( argumentNumber ) : NULL ;
const Token * argStart = arg ? arg - > typeStartToken ( ) : NULL ;
while ( argStart & & argStart - > previous ( ) & & argStart - > previous ( ) - > isName ( ) )
argStart = argStart - > previous ( ) ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( argStart , " const struct| %type% * const| %name% [,)] " ) )
2014-03-20 06:48:17 +01:00
return false ;
}
2014-05-10 20:20:55 +02:00
2014-09-09 11:11:41 +02:00
else if ( ftok & & Token : : simpleMatch ( ftok - > previous ( ) , " = * ( " ) )
2014-05-10 20:20:55 +02:00
return false ;
2014-03-20 06:48:17 +01:00
}
2013-01-24 19:41:15 +01:00
return true ;
2014-03-20 06:48:17 +01:00
}
2013-01-24 19:41:15 +01:00
return false ;
}
2015-01-23 19:38:39 +01:00
bool CheckUninitVar : : isMemberVariableUsage ( const Token * tok , bool isPointer , Alloc alloc , const std : : string & membervar ) const
2013-01-24 19:41:15 +01:00
{
2015-06-19 18:21:46 +02:00
if ( Token : : Match ( tok - > previous ( ) , " [(,] %name% . %name% [,)] " ) & &
tok - > strAt ( 2 ) = = membervar ) {
int use = isFunctionParUsage ( tok , isPointer , alloc ) ;
if ( use = = 1 )
return true ;
}
2013-01-24 19:41:15 +01:00
if ( isMemberVariableAssignment ( tok , membervar ) )
return false ;
2015-07-21 11:46:41 +02:00
if ( Token : : Match ( tok , " %name% . %name% " ) & & tok - > strAt ( 2 ) = = membervar & & ! ( tok - > tokAt ( - 2 ) - > variable ( ) & & tok - > tokAt ( - 2 ) - > variable ( ) - > isReference ( ) ) )
2013-01-24 19:41:15 +01:00
return true ;
2015-01-31 10:50:39 +01:00
else if ( ! isPointer & & Token : : Match ( tok - > previous ( ) , " [(,] %name% [,)] " ) & & isVariableUsage ( tok , isPointer , alloc ) )
2013-01-24 19:41:15 +01:00
return true ;
2015-01-31 10:50:39 +01:00
else if ( ! isPointer & & Token : : Match ( tok - > previous ( ) , " = %name% ; " ))
2014-05-10 19:56:44 +02:00
return true ;
2014-05-10 20:20:55 +02:00
// = *(&var);
else if ( ! isPointer & &
Token : : simpleMatch ( tok - > astParent ( ) , " & " ) & &
Token : : simpleMatch ( tok - > astParent ( ) - > astParent ( ) , " * " ) & &
Token : : Match ( tok - > astParent ( ) - > astParent ( ) - > astParent ( ) , " = * (| & " ) & &
tok - > astParent ( ) - > astParent ( ) - > astParent ( ) - > astOperand2 ( ) = = tok - > astParent ( ) - > astParent ( ) )
return true ;
2014-03-20 08:01:48 +01:00
else if ( _settings - > experimental & &
! isPointer & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tok - > tokAt ( - 2 ) , " [(,] & %name% [,)] " ) & &
2015-01-21 13:52:03 +01:00
isVariableUsage ( tok , isPointer , alloc ) )
2014-03-20 08:01:48 +01:00
return true ;
2014-03-20 07:19:35 +01:00
2013-01-24 19:41:15 +01:00
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
}
2014-08-05 06:24:23 +02:00
void CheckUninitVar : : deadPointer ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
std : : list < Scope > : : const_iterator scope ;
// check every executable scope
for ( scope = symbolDatabase - > scopeList . begin ( ) ; scope ! = symbolDatabase - > scopeList . end ( ) ; + + scope ) {
if ( ! scope - > isExecutable ( ) )
continue ;
// Dead pointers..
for ( const Token * tok = scope - > classStart ; tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
if ( tok - > variable ( ) & &
tok - > variable ( ) - > isPointer ( ) & &
2015-01-23 19:38:39 +01:00
isVariableUsage ( tok , true , NO_ALLOC ) ) {
2014-08-05 06:24:23 +02:00
const Token * alias = tok - > getValueTokenDeadPointer ( ) ;
if ( alias ) {
deadPointerError ( tok , alias ) ;
}
}
}
}
}
void CheckUninitVar : : deadPointerError ( const Token * pointer , const Token * alias )
{
const std : : string strpointer ( pointer ? pointer - > str ( ) : std : : string ( " pointer " ) ) ;
const std : : string stralias ( alias ? alias - > expressionString ( ) : std : : string ( " &x " ) ) ;
reportError ( pointer ,
Severity : : error ,
" deadpointer " ,
" Dead pointer usage. Pointer ' " + strpointer + " ' is dead if it has been assigned ' " + stralias + " ' at line " + MathLib : : toString ( alias ? alias - > linenr ( ) : 0U ) + " . " ) ;
}