2014-01-04 20:57:02 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2014-02-15 07:45:39 +01:00
* Copyright ( C ) 2007 - 2014 Daniel Marjamäki and Cppcheck team .
2014-01-04 20:57:02 +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 "valueflow.h"
2014-01-05 20:06:46 +01:00
# include "errorlogger.h"
2014-01-04 20:57:02 +01:00
# include "mathlib.h"
2014-01-05 20:06:46 +01:00
# include "settings.h"
# include "symboldatabase.h"
# include "token.h"
# include "tokenlist.h"
2014-01-04 20:57:02 +01:00
2014-05-23 20:58:28 +02:00
//#include <iostream>
2014-01-19 09:05:48 +01:00
# include <stack>
2014-01-06 16:37:52 +01:00
2014-05-01 15:15:26 +02:00
static void execute ( const Token * expr ,
std : : map < unsigned int , MathLib : : bigint > * const programMemory ,
MathLib : : bigint * result ,
bool * error ) ;
2014-04-26 20:44:21 +02:00
//static void printvalues(const Token *tok)
//{
// if (tok->values.empty())
// std::cout << "empty";
// for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it)
// std::cout << " " << (it->intvalue);
// std::cout << std::endl;
//}
2014-01-06 16:37:52 +01:00
2014-01-06 07:44:58 +01:00
static void bailout ( TokenList * tokenlist , ErrorLogger * errorLogger , const Token * tok , const std : : string & what )
{
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callstack ;
callstack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( tok , tokenlist ) ) ;
ErrorLogger : : ErrorMessage errmsg ( callstack , Severity : : debug , " ValueFlow bailout: " + what , " valueFlowBailout " , false ) ;
errorLogger - > reportErr ( errmsg ) ;
}
2014-01-12 19:48:20 +01:00
static bool bailoutFunctionPar ( const Token * tok , const ValueFlow : : Value & value , const Settings * settings , bool * inconclusive )
2014-01-11 14:31:51 +01:00
{
2014-01-24 17:47:49 +01:00
if ( ! tok )
return false ;
// address of variable
2014-03-14 16:26:37 +01:00
const bool addressOf = tok & & Token : : simpleMatch ( tok - > previous ( ) , " & " ) ;
2014-01-24 17:47:49 +01:00
// passing variable to subfunction?
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " ) & %var% [,)] " ) & & Token : : Match ( tok - > linkAt ( - 2 ) - > previous ( ) , " [,(] ( " ) )
;
else if ( Token : : Match ( tok - > tokAt ( addressOf ? - 2 : - 1 ) , " [(,] &| %var% [,)] " ) )
;
else
2014-01-11 14:31:51 +01:00
return false ;
2014-04-01 07:06:20 +02:00
// reinterpret_cast etc..
if ( Token : : Match ( tok - > tokAt ( - 3 ) , " > ( & %var% ) [,)] " ) & &
tok - > linkAt ( - 3 ) & &
Token : : Match ( tok - > linkAt ( - 3 ) - > tokAt ( - 2 ) , " [,(] %type% < " ) )
tok = tok - > linkAt ( - 3 ) ;
2014-01-11 14:31:51 +01:00
// goto start of function call and get argnr
unsigned int argnr = 0 ;
while ( tok & & tok - > str ( ) ! = " ( " ) {
if ( tok - > str ( ) = = " , " )
+ + argnr ;
else if ( tok - > str ( ) = = " ) " )
tok = tok - > link ( ) ;
tok = tok - > previous ( ) ;
}
2014-02-16 10:32:10 +01:00
tok = tok ? tok - > previous ( ) : nullptr ;
2014-01-11 14:31:51 +01:00
if ( ! Token : : Match ( tok , " %var% ( " ) )
2014-02-27 16:40:42 +01:00
return false ; // not a function => do not bailout
2014-01-11 14:31:51 +01:00
2014-01-12 18:19:00 +01:00
if ( ! tok - > function ( ) ) {
2014-02-27 16:40:42 +01:00
// if value is 0 and the library says 0 is invalid => do not bailout
2014-01-12 19:48:20 +01:00
if ( value . intvalue = = 0 & & settings - > library . isnullargbad ( tok - > str ( ) , 1 + argnr ) )
return false ;
2014-03-18 17:04:33 +01:00
// addressOf => inconclusive
if ( ! addressOf ) {
2014-01-12 19:48:20 +01:00
* inconclusive = true ;
return false ;
}
return true ;
2014-01-12 18:19:00 +01:00
}
2014-01-11 14:31:51 +01:00
const Variable * arg = tok - > function ( ) - > getArgumentVar ( argnr ) ;
2014-01-13 05:52:28 +01:00
if ( addressOf & & ! ( arg & & arg - > isConst ( ) ) )
return true ;
2014-01-11 14:31:51 +01:00
return arg & & ! arg - > isConst ( ) & & arg - > isReference ( ) ;
}
2014-05-01 15:15:26 +02:00
/**
* Is condition always false when variable has given value ?
* \ param condition top ast token in condition
* \ param varid variable id for variable
* \ param value value of variable
*/
static bool conditionIsFalse ( const Token * condition , unsigned int varid , const ValueFlow : : Value & value )
{
if ( ! condition )
return false ;
if ( condition - > str ( ) = = " && " ) {
bool result1 = conditionIsFalse ( condition - > astOperand1 ( ) , varid , value ) ;
bool result2 = result1 ? true : conditionIsFalse ( condition - > astOperand2 ( ) , varid , value ) ;
return result2 ;
}
std : : map < unsigned int , MathLib : : bigint > programMemory ;
programMemory [ varid ] = value . intvalue ;
MathLib : : bigint result = 0 ;
bool error = false ;
execute ( condition , & programMemory , & result , & error ) ;
return ! error & & result = = 0 ;
}
2014-06-25 16:00:56 +02:00
/**
* Is condition always true when variable has given value ?
* \ param condition top ast token in condition
* \ param varid variable id for variable
* \ param value value of variable
*/
static bool conditionIsTrue ( const Token * condition , unsigned int varid , const ValueFlow : : Value & value )
{
if ( ! condition )
return false ;
if ( condition - > str ( ) = = " || " ) {
bool result1 = conditionIsTrue ( condition - > astOperand1 ( ) , varid , value ) ;
bool result2 = result1 ? true : conditionIsTrue ( condition - > astOperand2 ( ) , varid , value ) ;
return result2 ;
}
std : : map < unsigned int , MathLib : : bigint > programMemory ;
programMemory [ varid ] = value . intvalue ;
MathLib : : bigint result = 0 ;
bool error = false ;
execute ( condition , & programMemory , & result , & error ) ;
return ! error & & result = = 1 ;
}
2014-01-19 09:05:48 +01:00
/**
* Should value be skipped because it ' s hidden inside & & | | or ? : expression .
* Example : ( ( x ! = NULL ) & & ( * x = = 123 ) )
* If ' valuetok ' points at the x in ' ( * x = = 123 ) ' . Then the ' & & ' will be returned .
* @ param valuetok original variable token
* @ return NULL = > don ' t skip , non - NULL = > The operator token that cause the skip . For instance the ' & & ' .
* */
static const Token * skipValueInConditionalExpression ( const Token * const valuetok )
2014-01-11 14:54:10 +01:00
{
2014-01-19 09:05:48 +01:00
// Walk up the ast
2014-01-19 09:31:40 +01:00
const Token * prev = valuetok ;
2014-01-19 09:05:48 +01:00
for ( const Token * tok = valuetok - > astParent ( ) ; tok ; tok = tok - > astParent ( ) ) {
2014-01-19 09:31:40 +01:00
const bool prevIsLhs = ( prev = = tok - > astOperand1 ( ) ) ;
prev = tok ;
if ( prevIsLhs | | ! Token : : Match ( tok , " %oror%|&&|?|: " ) )
2014-01-19 09:05:48 +01:00
continue ;
// Is variable protected in LHS..
std : : stack < const Token * > tokens ;
tokens . push ( tok - > astOperand1 ( ) ) ;
while ( ! tokens . empty ( ) ) {
const Token * const tok2 = tokens . top ( ) ;
tokens . pop ( ) ;
if ( ! tok2 )
continue ;
if ( tok2 ! = valuetok & & tok2 - > str ( ) = = valuetok - > str ( ) )
return tok ;
tokens . push ( tok2 - > astOperand2 ( ) ) ;
tokens . push ( tok2 - > astOperand1 ( ) ) ;
}
2014-01-11 14:54:10 +01:00
}
2014-02-16 10:32:10 +01:00
return nullptr ;
2014-01-11 14:54:10 +01:00
}
2014-01-11 15:36:09 +01:00
static bool bailoutSelfAssignment ( const Token * const tok )
{
const Token * parent = tok ;
while ( parent ) {
const Token * op = parent ;
parent = parent - > astParent ( ) ;
// Assignment where lhs variable exists in rhs => return true
2014-02-16 10:32:10 +01:00
if ( parent ! = nullptr & &
2014-01-11 20:53:23 +01:00
parent - > astOperand2 ( ) = = op & &
2014-02-16 10:32:10 +01:00
parent - > astOperand1 ( ) ! = nullptr & &
2014-01-11 20:53:23 +01:00
parent - > str ( ) = = " = " ) {
for ( const Token * lhs = parent - > astOperand1 ( ) ; lhs ; lhs = lhs - > astOperand1 ( ) ) {
if ( lhs - > varId ( ) = = tok - > varId ( ) )
return true ;
if ( lhs - > astOperand2 ( ) & & lhs - > astOperand2 ( ) - > varId ( ) = = tok - > varId ( ) )
return true ;
}
}
2014-01-11 15:36:09 +01:00
}
return false ;
}
2014-04-20 14:21:43 +02:00
static bool isVariableChanged ( const Token * start , const Token * end , const unsigned int varid )
{
for ( const Token * tok = start ; tok ! = end ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) = = varid ) {
if ( Token : : Match ( tok , " %var% = " ) )
return true ;
const Token * parent = tok - > astParent ( ) ;
while ( parent & & parent - > str ( ) = = " . " )
parent = parent - > astParent ( ) ;
2014-05-11 13:37:53 +02:00
if ( parent & & parent - > type ( ) = = Token : : eIncDecOp )
2014-04-20 14:21:43 +02:00
return true ;
}
}
return false ;
}
2014-01-18 19:30:44 +01:00
/** set ValueFlow value and perform calculations if possible */
static void setTokenValue ( Token * tok , const ValueFlow : : Value & value )
{
// if value already exists, don't add it again
std : : list < ValueFlow : : Value > : : iterator it ;
for ( it = tok - > values . begin ( ) ; it ! = tok - > values . end ( ) ; + + it ) {
if ( it - > intvalue = = value . intvalue ) {
if ( it - > inconclusive & & ! value . inconclusive ) {
* it = value ;
break ;
}
return ;
}
}
if ( it = = tok - > values . end ( ) ) {
tok - > values . push_back ( value ) ;
it = tok - > values . end ( ) ;
- - it ;
}
Token * parent = const_cast < Token * > ( tok - > astParent ( ) ) ;
2014-01-20 22:26:55 +01:00
// Cast..
if ( parent & & parent - > str ( ) = = " ( " & & tok = = parent - > link ( ) - > next ( ) ) {
setTokenValue ( parent , value ) ;
}
// Calculations..
else if ( parent & & parent - > isArithmeticalOp ( ) & & parent - > astOperand1 ( ) & & parent - > astOperand2 ( ) ) {
2014-01-18 19:30:44 +01:00
std : : list < ValueFlow : : Value > : : const_iterator value1 , value2 ;
for ( value1 = parent - > astOperand1 ( ) - > values . begin ( ) ; value1 ! = parent - > astOperand1 ( ) - > values . end ( ) ; + + value1 ) {
for ( value2 = parent - > astOperand2 ( ) - > values . begin ( ) ; value2 ! = parent - > astOperand2 ( ) - > values . end ( ) ; + + value2 ) {
2014-01-20 21:45:30 +01:00
if ( value1 - > varId = = 0U | | value2 - > varId = = 0U | |
( value1 - > varId = = value2 - > varId & & value1 - > varvalue = = value2 - > varvalue ) ) {
2014-01-18 19:30:44 +01:00
ValueFlow : : Value result ( 0 ) ;
result . condition = value1 - > condition ? value1 - > condition : value2 - > condition ;
result . inconclusive = value1 - > inconclusive | value2 - > inconclusive ;
result . varId = ( value1 - > varId ! = 0U ) ? value1 - > varId : value2 - > varId ;
2014-01-20 21:45:30 +01:00
result . varvalue = ( result . varId = = value1 - > varId ) ? value1 - > intvalue : value2 - > intvalue ;
2014-01-18 19:30:44 +01:00
switch ( parent - > str ( ) [ 0 ] ) {
case ' + ' :
result . intvalue = value1 - > intvalue + value2 - > intvalue ;
setTokenValue ( parent , result ) ;
break ;
case ' - ' :
result . intvalue = value1 - > intvalue - value2 - > intvalue ;
setTokenValue ( parent , result ) ;
break ;
case ' * ' :
result . intvalue = value1 - > intvalue * value2 - > intvalue ;
setTokenValue ( parent , result ) ;
break ;
case ' / ' :
if ( value2 - > intvalue = = 0 )
break ;
result . intvalue = value1 - > intvalue / value2 - > intvalue ;
setTokenValue ( parent , result ) ;
break ;
case ' % ' :
if ( value2 - > intvalue = = 0 )
break ;
result . intvalue = value1 - > intvalue % value2 - > intvalue ;
setTokenValue ( parent , result ) ;
break ;
}
}
}
}
}
}
static void valueFlowNumber ( TokenList * tokenlist )
{
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > isNumber ( ) & & MathLib : : isInt ( tok - > str ( ) ) )
setTokenValue ( tok , ValueFlow : : Value ( MathLib : : toLongNumber ( tok - > str ( ) ) ) ) ;
}
}
2014-04-14 06:45:39 +02:00
static void valueFlowBitAnd ( TokenList * tokenlist )
{
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) ! = " & " )
continue ;
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
continue ;
MathLib : : bigint number ;
if ( MathLib : : isInt ( tok - > astOperand1 ( ) - > str ( ) ) )
number = MathLib : : toLongNumber ( tok - > astOperand1 ( ) - > str ( ) ) ;
else if ( MathLib : : isInt ( tok - > astOperand2 ( ) - > str ( ) ) )
number = MathLib : : toLongNumber ( tok - > astOperand2 ( ) - > str ( ) ) ;
else
continue ;
int bit = 0 ;
while ( bit < = 60 & & ( ( 1LL < < bit ) < number ) )
+ + bit ;
if ( ( 1LL < < bit ) = = number ) {
setTokenValue ( tok , ValueFlow : : Value ( 0 ) ) ;
setTokenValue ( tok , ValueFlow : : Value ( number ) ) ;
}
}
}
2014-01-05 20:06:46 +01:00
static void valueFlowBeforeCondition ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
2014-01-04 20:57:02 +01:00
{
2014-01-05 20:06:46 +01:00
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
2014-03-30 10:22:06 +02:00
unsigned int varid = 0 ;
MathLib : : bigint num = 0 ;
const Variable * var = 0 ;
2014-01-10 05:54:03 +01:00
if ( tok - > isComparisonOp ( ) & & tok - > astOperand1 ( ) & & tok - > astOperand2 ( ) ) {
2014-01-04 20:57:02 +01:00
if ( tok - > astOperand1 ( ) - > isName ( ) & & tok - > astOperand2 ( ) - > isNumber ( ) ) {
varid = tok - > astOperand1 ( ) - > varId ( ) ;
2014-01-05 20:06:46 +01:00
var = tok - > astOperand1 ( ) - > variable ( ) ;
2014-01-04 21:23:17 +01:00
num = MathLib : : toLongNumber ( tok - > astOperand2 ( ) - > str ( ) ) ;
2014-01-04 20:57:02 +01:00
} else if ( tok - > astOperand1 ( ) - > isNumber ( ) & & tok - > astOperand2 ( ) - > isName ( ) ) {
varid = tok - > astOperand2 ( ) - > varId ( ) ;
2014-01-05 20:06:46 +01:00
var = tok - > astOperand2 ( ) - > variable ( ) ;
2014-01-04 20:57:02 +01:00
num = MathLib : : toLongNumber ( tok - > astOperand1 ( ) - > str ( ) ) ;
} else {
continue ;
}
} else if ( Token : : Match ( tok - > previous ( ) , " if|while ( %var% %oror%|&&|) " ) | |
Token : : Match ( tok , " %oror%|&& %var% %oror%|&&|) " ) ) {
varid = tok - > next ( ) - > varId ( ) ;
2014-01-05 20:06:46 +01:00
var = tok - > next ( ) - > variable ( ) ;
2014-01-04 20:57:02 +01:00
num = 0 ;
} else if ( tok - > str ( ) = = " ! " & & tok - > astOperand1 ( ) & & tok - > astOperand1 ( ) - > isName ( ) ) {
varid = tok - > astOperand1 ( ) - > varId ( ) ;
2014-01-05 20:06:46 +01:00
var = tok - > astOperand1 ( ) - > variable ( ) ;
2014-01-04 20:57:02 +01:00
num = 0 ;
} else {
continue ;
}
2014-01-12 11:58:10 +01:00
if ( varid = = 0U | | ! var )
2014-01-04 20:57:02 +01:00
continue ;
2014-01-10 05:47:56 +01:00
// bailout: global non-const variables
2014-01-19 11:55:02 +01:00
if ( ! ( var - > isLocal ( ) | | var - > isArgument ( ) ) & & ! var - > isConst ( ) ) {
2014-01-06 07:44:58 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " global variable " + var - > nameToken ( ) - > str ( ) ) ;
continue ;
}
2014-01-25 09:22:32 +01:00
// bailout: for/while-condition, variable is changed in while loop
2014-01-15 17:32:14 +01:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > astParent ( ) ) {
if ( tok2 - > astParent ( ) | | tok2 - > str ( ) ! = " ( " | | ! Token : : simpleMatch ( tok2 - > link ( ) , " ) { " ) )
continue ;
2014-01-14 17:57:50 +01:00
2014-01-15 17:32:14 +01:00
if ( Token : : Match ( tok2 - > previous ( ) , " for|while ( " ) ) {
2014-03-21 08:33:45 +01:00
const Token * const start = tok2 - > link ( ) - > next ( ) ;
const Token * const end = start - > link ( ) ;
2014-01-25 09:22:32 +01:00
2014-04-20 14:21:43 +02:00
if ( isVariableChanged ( start , end , varid ) ) {
2014-01-12 17:16:51 +01:00
varid = 0U ;
if ( settings - > debugwarnings )
2014-01-15 17:32:14 +01:00
bailout ( tokenlist , errorLogger , tok , " variable " + var - > nameToken ( ) - > str ( ) + " used in loop " ) ;
2014-01-11 20:25:49 +01:00
}
}
2014-01-14 17:57:50 +01:00
2014-01-15 17:32:14 +01:00
// if,macro => bailout
else if ( Token : : simpleMatch ( tok2 - > previous ( ) , " if ( " ) & & tok2 - > previous ( ) - > isExpandedMacro ( ) ) {
varid = 0U ;
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " variable " + var - > nameToken ( ) - > str ( ) + " , condition is defined in macro " ) ;
}
2014-01-11 20:25:49 +01:00
}
2014-01-12 17:16:51 +01:00
if ( varid = = 0U )
2014-01-11 20:25:49 +01:00
continue ;
// extra logic for unsigned variables 'i>=1' => possible value can also be 0
2014-01-17 19:28:28 +01:00
ValueFlow : : Value val ( tok , num ) ;
2014-01-18 19:30:44 +01:00
val . varId = varid ;
2014-01-08 06:53:17 +01:00
ValueFlow : : Value val2 ;
2014-01-12 12:38:41 +01:00
if ( num = = 1U & & Token : : Match ( tok , " <=|>= " ) ) {
2014-01-13 20:54:09 +01:00
bool isunsigned = false ;
for ( const Token * type = var - > typeStartToken ( ) ; type & & type - > varId ( ) = = 0U ; type = type - > next ( ) )
2014-01-11 07:52:25 +01:00
isunsigned | = type - > isUnsigned ( ) ;
2014-01-18 19:30:44 +01:00
if ( isunsigned ) {
2014-01-11 07:52:25 +01:00
val2 = ValueFlow : : Value ( tok , 0 ) ;
2014-01-18 19:30:44 +01:00
val2 . varId = varid ;
}
2014-01-11 07:52:25 +01:00
}
2014-01-19 20:16:55 +01:00
if ( Token : : Match ( tok , " <|> " ) ) {
if ( num ! = 0 )
continue ;
bool isunsigned = false ;
for ( const Token * type = var - > typeStartToken ( ) ; type & & type - > varId ( ) = = 0U ; type = type - > next ( ) )
isunsigned | = type - > isUnsigned ( ) ;
if ( ! isunsigned )
continue ;
}
2014-01-05 20:06:46 +01:00
for ( Token * tok2 = tok - > previous ( ) ; ; tok2 = tok2 - > previous ( ) ) {
if ( ! tok2 ) {
if ( settings - > debugwarnings ) {
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callstack ;
callstack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( tok , tokenlist ) ) ;
ErrorLogger : : ErrorMessage errmsg ( callstack , Severity : : debug , " iterated too far " , " debugValueFlowBeforeCondition " , false ) ;
errorLogger - > reportErr ( errmsg ) ;
}
break ;
}
2014-01-10 16:51:58 +01:00
2014-01-05 20:06:46 +01:00
if ( tok2 - > varId ( ) = = varid ) {
2014-01-06 07:44:58 +01:00
// bailout: assignment
2014-01-08 17:37:39 +01:00
if ( Token : : Match ( tok2 - > previous ( ) , " !!* %var% = " ) ) {
2014-01-06 07:44:58 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " assignment of " + tok2 - > str ( ) ) ;
2014-01-06 10:23:17 +01:00
break ;
2014-01-06 07:44:58 +01:00
}
2014-01-17 19:28:28 +01:00
// increment/decrement
if ( Token : : Match ( tok2 - > previous ( ) , " [;{}] %var% ++|-- ; " ) )
val . intvalue + = ( tok2 - > strAt ( 1 ) = = " ++ " ) ? - 1 : 1 ;
else if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [ ; { } ] + + | - - % var % ; " ))
val . intvalue + = ( tok2 - > strAt ( - 1 ) = = " ++ " ) ? - 1 : 1 ;
else if ( Token : : Match ( tok2 - > previous ( ) , " ++|-- %var% " ) | | Token : : Match ( tok2 , " %var% ++|-- " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " increment/decrement of " + tok2 - > str ( ) ) ;
break ;
}
2014-01-11 15:36:09 +01:00
// bailout: variable is used in rhs in assignment to itself
if ( bailoutSelfAssignment ( tok2 ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + tok2 - > str ( ) + " is used in rhs in assignment to itself " ) ;
break ;
}
2014-04-29 20:09:11 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " sizeof|. " ) ) {
const Token * prev = tok2 - > previous ( ) ;
while ( Token : : Match ( prev , " %var%|. " ) & & prev - > str ( ) ! = " sizeof " )
prev = prev - > previous ( ) ;
2014-05-18 20:39:52 +02:00
if ( prev & & prev - > str ( ) = = " sizeof " )
2014-04-29 20:09:11 +02:00
continue ;
}
2014-01-11 14:31:51 +01:00
// assigned by subfunction?
2014-01-18 19:51:57 +01:00
bool inconclusive = false ;
if ( bailoutFunctionPar ( tok2 , val2 . condition ? val2 : val , settings , & inconclusive ) ) {
2014-01-11 14:31:51 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " possible assignment of " + tok2 - > str ( ) + " by subfunction " ) ;
break ;
}
2014-01-18 19:51:57 +01:00
val . inconclusive | = inconclusive ;
val2 . inconclusive | = inconclusive ;
2014-01-11 14:31:51 +01:00
2014-01-11 14:54:10 +01:00
// skip if variable is conditionally used in ?: expression
if ( const Token * parent = skipValueInConditionalExpression ( tok2 ) ) {
2014-01-08 06:39:15 +01:00
if ( settings - > debugwarnings )
2014-01-11 12:44:55 +01:00
bailout ( tokenlist ,
errorLogger ,
tok2 ,
2014-01-11 11:30:34 +01:00
" no simplification of " + tok2 - > str ( ) + " within " + ( Token : : Match ( parent , " [?:] " ) ? " ?: " : parent - > str ( ) ) + " expression " ) ;
2014-01-08 06:39:15 +01:00
continue ;
}
2014-01-18 19:30:44 +01:00
setTokenValue ( tok2 , val ) ;
2014-01-08 06:53:17 +01:00
if ( val2 . condition )
2014-01-18 19:30:44 +01:00
setTokenValue ( tok2 , val2 ) ;
2014-01-05 20:06:46 +01:00
if ( var & & tok2 = = var - > nameToken ( ) )
2014-01-04 20:57:02 +01:00
break ;
}
2014-01-06 11:27:56 +01:00
2014-01-11 21:10:01 +01:00
// skip sizeof..
if ( tok2 - > str ( ) = = " ) " & & Token : : Match ( tok2 - > link ( ) - > previous ( ) , " typeof|sizeof ( " ) )
tok2 = tok2 - > link ( ) ;
2014-04-28 06:21:48 +02:00
// goto label
if ( Token : : Match ( tok2 , " [;{}] %var% : " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 - > next ( ) , " variable " + var - > nameToken ( ) - > str ( ) + " stopping on goto label " ) ;
break ;
}
2014-01-06 11:27:56 +01:00
if ( tok2 - > str ( ) = = " } " ) {
2014-01-10 16:13:39 +01:00
if ( Token : : findmatch ( tok2 - > link ( ) , " %varid% " , tok2 , varid ) ) {
2014-04-02 19:08:44 +02:00
if ( settings - > debugwarnings ) {
2014-04-02 19:22:40 +02:00
std : : string errmsg = " variable " ;
2014-04-02 19:08:44 +02:00
if ( var )
errmsg + = var - > nameToken ( ) - > str ( ) + " " ;
errmsg + = " stopping on } " ;
bailout ( tokenlist , errorLogger , tok2 , errmsg ) ;
}
2014-01-10 16:13:39 +01:00
break ;
} else {
tok2 = tok2 - > link ( ) ;
}
2014-01-12 11:58:10 +01:00
} else if ( tok2 - > str ( ) = = " { " ) {
// if variable is assigned in loop don't look before the loop
if ( tok2 - > previous ( ) & &
2014-03-14 16:26:37 +01:00
( Token : : simpleMatch ( tok2 - > previous ( ) , " do " ) | |
2014-01-18 11:54:00 +01:00
( tok2 - > strAt ( - 1 ) = = " ) " & & Token : : Match ( tok2 - > linkAt ( - 1 ) - > previous ( ) , " for|while ( " ) ) ) ) {
2014-01-12 11:58:10 +01:00
const Token * start = tok2 ;
const Token * end = start - > link ( ) ;
2014-04-20 14:21:43 +02:00
if ( isVariableChanged ( start , end , varid ) ) {
2014-01-12 11:58:10 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " is assigned in loop. so valueflow analysis bailout when start of loop is reached. " ) ;
break ;
}
}
// Global variable : stop when leaving the function scope
2014-01-12 14:37:26 +01:00
if ( ! var - > isLocal ( ) ) {
2014-01-12 15:02:58 +01:00
if ( ! Token : : Match ( tok2 - > previous ( ) , " )|else|do { " ) )
2014-01-12 11:58:10 +01:00
break ;
2014-03-14 16:26:37 +01:00
if ( Token : : simpleMatch ( tok2 - > previous ( ) , " ) { " ) & &
2014-01-12 11:58:10 +01:00
! Token : : Match ( tok2 - > linkAt ( - 1 ) - > previous ( ) , " if|for|while ( " ) )
break ;
}
2014-01-12 15:07:58 +01:00
} else if ( tok2 - > str ( ) = = " ; " ) {
const Token * parent = tok2 - > previous ( ) ;
while ( parent & & ! Token : : Match ( parent , " return|break|continue|goto " ) )
parent = parent - > astParent ( ) ;
// reaching a break/continue/return
if ( parent ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " stopping on " + parent - > str ( ) ) ;
break ;
}
2014-01-10 16:51:58 +01:00
}
2014-01-04 20:57:02 +01:00
}
}
}
2014-06-18 05:51:23 +02:00
static bool valueFlowForward ( Token * const startToken ,
2014-06-15 16:47:01 +02:00
const Token * const endToken ,
const Variable * const var ,
const unsigned int varid ,
std : : list < ValueFlow : : Value > values ,
const bool constValue ,
TokenList * const tokenlist ,
ErrorLogger * const errorLogger ,
const Settings * const settings )
{
int indentlevel = 0 ;
unsigned int number_of_if = 0 ;
int varusagelevel = - 1 ;
bool returnStatement = false ; // current statement is a return, stop analysis at the ";"
for ( Token * tok2 = startToken ; tok2 & & tok2 ! = endToken ; tok2 = tok2 - > next ( ) ) {
if ( indentlevel > = 0 & & tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( indentlevel > = 0 & & tok2 - > str ( ) = = " } " )
- - indentlevel ;
if ( Token : : Match ( tok2 , " sizeof|typeof|typeid ( " ) )
tok2 = tok2 - > linkAt ( 1 ) ;
2014-06-25 16:00:56 +02:00
else if ( Token : : simpleMatch ( tok2 , " else { " ) ) {
// Should scope be skipped because variable value is checked?
bool skipelse = false ;
const Token * condition = tok2 - > linkAt ( - 1 ) ;
condition = condition ? condition - > linkAt ( - 1 ) : nullptr ;
condition = condition ? condition - > astOperand2 ( ) : nullptr ;
for ( std : : list < ValueFlow : : Value > : : iterator it = values . begin ( ) ; it ! = values . end ( ) ; + + it ) {
if ( conditionIsTrue ( condition , varid , * it ) ) {
skipelse = true ;
break ;
}
}
if ( skipelse ) {
tok2 = tok2 - > linkAt ( 1 ) ;
continue ;
}
}
2014-06-15 16:47:01 +02:00
// conditional block of code that assigns variable..
else if ( Token : : Match ( tok2 , " %var% ( " ) & & Token : : simpleMatch ( tok2 - > linkAt ( 1 ) , " ) { " )) {
// Should scope be skipped because variable value is checked?
bool skip = false ;
for ( std : : list < ValueFlow : : Value > : : iterator it = values . begin ( ) ; it ! = values . end ( ) ; + + it ) {
if ( conditionIsFalse ( tok2 - > next ( ) - > astOperand2 ( ) , varid , * it ) ) {
skip = true ;
break ;
}
}
if ( skip ) {
// goto '{'
tok2 = tok2 - > linkAt ( 1 ) - > next ( ) ;
// goto '}'
tok2 = tok2 - > link ( ) ;
continue ;
}
Token * const start = tok2 - > linkAt ( 1 ) - > next ( ) ;
Token * const end = start - > link ( ) ;
bool varusage = ( indentlevel > = 0 & & constValue & & number_of_if = = 0U ) ?
isVariableChanged ( start , end , varid ) :
( nullptr ! = Token : : findmatch ( start , " %varid% " , end , varid ) ) ;
if ( varusage ) {
varusagelevel = indentlevel ;
// TODO: don't check noreturn scopes
if ( number_of_if > 0U | | Token : : findmatch ( tok2 , " %varid% " , start , varid ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " is assigned in conditional code " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
if ( var - > isStatic ( ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " bailout when conditional code that contains var is seen " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
// Remove conditional values
std : : list < ValueFlow : : Value > : : iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; ) {
if ( it - > condition | | it - > conditional )
values . erase ( it + + ) ;
else
+ + it ;
}
}
// noreturn scopes..
if ( ( number_of_if > 0 | | Token : : findmatch ( tok2 , " %varid% " , start , varid ) ) & &
2014-06-18 05:51:23 +02:00
( Token : : findmatch ( start , " return|continue|break|throw " , end ) | |
( Token : : simpleMatch ( end , " } else { " ) & & Token : : findmatch ( end , " return|continue|break|throw " , end - > linkAt ( 2 ) ) ) ) ) {
2014-06-15 16:47:01 +02:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " . noreturn conditional scope. " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
if ( isVariableChanged ( start , end , varid ) ) {
if ( number_of_if = = 0 & &
Token : : simpleMatch ( tok2 , " if ( " ) & &
! ( Token : : simpleMatch ( end , " } else { " ) & &
( Token : : findmatch ( end , " %varid% " , end - > linkAt ( 2 ) , varid ) | |
2014-06-18 05:51:23 +02:00
Token : : findmatch ( end , " return|continue|break|throw " , end - > linkAt ( 2 ) ) ) ) ) {
2014-06-15 16:47:01 +02:00
+ + number_of_if ;
tok2 = end ;
} else {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " is assigned in conditional code " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
}
}
else if ( tok2 - > str ( ) = = " } " & & indentlevel = = varusagelevel ) {
+ + number_of_if ;
// Set "conditional" flag for all values
std : : list < ValueFlow : : Value > : : iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
it - > conditional = true ;
if ( Token : : simpleMatch ( tok2 , " } else { " ) )
tok2 = tok2 - > linkAt ( 2 ) ;
}
else if ( indentlevel < = 0 & & Token : : Match ( tok2 , " break|continue|goto " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " . noreturn conditional scope. " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
2014-06-18 05:51:23 +02:00
else if ( indentlevel < = 0 & & Token : : Match ( tok2 , " return|throw " ) )
2014-06-15 16:47:01 +02:00
returnStatement = true ;
else if ( returnStatement & & tok2 - > str ( ) = = " ; " )
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
if ( tok2 - > varId ( ) = = varid ) {
// bailout: assignment
if ( Token : : Match ( tok2 - > previous ( ) , " !!* %var% %op% " ) & & tok2 - > next ( ) - > isAssignmentOp ( ) ) {
2014-06-18 21:07:01 +02:00
// simplify rhs
for ( Token * tok3 = tok2 - > tokAt ( 2 ) ; tok3 ; tok3 = tok3 - > next ( ) ) {
if ( tok3 - > varId ( ) = = varid ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
setTokenValue ( tok2 , * it ) ;
} else if ( Token : : Match ( tok3 , " ++|--|?|:|; " ) )
break ;
}
2014-06-15 16:47:01 +02:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " assignment of " + tok2 - > str ( ) ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
// bailout increment/decrement for now..
if ( Token : : Match ( tok2 - > previous ( ) , " ++|-- %var% " ) | | Token : : Match ( tok2 , " %var% ++|-- " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " increment/decrement of " + tok2 - > str ( ) ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
// bailout: possible assignment using >>
if ( Token : : Match ( tok2 - > previous ( ) , " >> %var% >>|; " ) ) {
const Token * parent = tok2 - > previous ( ) ;
while ( Token : : simpleMatch ( parent , " >> " ) )
parent = parent - > astParent ( ) ;
if ( ! parent ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " Possible assignment of " + tok2 - > str ( ) + " using >> " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
}
// skip if variable is conditionally used in ?: expression
if ( const Token * parent = skipValueInConditionalExpression ( tok2 ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist ,
errorLogger ,
tok2 ,
" no simplification of " + tok2 - > str ( ) + " within " + ( Token : : Match ( parent , " [?:] " ) ? " ?: " : parent - > str ( ) ) + " expression " ) ;
continue ;
}
{
std : : list < ValueFlow : : Value > : : const_iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
setTokenValue ( tok2 , * it ) ;
}
// assigned by subfunction?
bool inconclusive = false ;
if ( bailoutFunctionPar ( tok2 , ValueFlow : : Value ( ) , settings , & inconclusive ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " possible assignment of " + tok2 - > str ( ) + " by subfunction " ) ;
2014-06-18 05:51:23 +02:00
return false ;
2014-06-15 16:47:01 +02:00
}
if ( inconclusive ) {
std : : list < ValueFlow : : Value > : : iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
it - > inconclusive = true ;
}
}
}
2014-06-18 05:51:23 +02:00
return true ;
2014-06-15 16:47:01 +02:00
}
2014-01-21 21:13:49 +01:00
static void valueFlowAfterAssign ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
// Assignment
if ( ( tok - > str ( ) ! = " = " ) | | ( tok - > astParent ( ) ) )
continue ;
2014-01-23 19:40:47 +01:00
// Lhs should be a variable
2014-01-21 21:13:49 +01:00
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand1 ( ) - > isName ( ) )
continue ;
2014-01-24 06:16:23 +01:00
const unsigned int varid = tok - > astOperand1 ( ) - > varId ( ) ;
2014-01-21 21:13:49 +01:00
if ( varid = = 0U )
continue ;
const Variable * var = tok - > astOperand1 ( ) - > variable ( ) ;
if ( ! var | | ! var - > isLocal ( ) )
continue ;
2014-01-22 20:16:31 +01:00
const Token * endToken = 0 ;
for ( const Token * tok2 = var - > typeStartToken ( ) ; tok2 ; tok2 = tok2 - > previous ( ) ) {
if ( tok2 - > str ( ) = = " { " ) {
endToken = tok2 - > link ( ) ;
break ;
}
}
2014-01-21 21:13:49 +01:00
2014-01-23 19:40:47 +01:00
// Rhs values..
2014-01-21 21:13:49 +01:00
if ( ! tok - > astOperand2 ( ) | | tok - > astOperand2 ( ) - > values . empty ( ) )
continue ;
std : : list < ValueFlow : : Value > values = tok - > astOperand2 ( ) - > values ;
2014-04-22 16:10:20 +02:00
const bool constValue = tok - > astOperand2 ( ) - > isNumber ( ) ;
2014-06-15 16:47:01 +02:00
valueFlowForward ( tok , endToken , var , varid , values , constValue , tokenlist , errorLogger , settings ) ;
}
}
2014-02-22 12:09:54 +01:00
2014-06-15 16:47:01 +02:00
static void valueFlowAfterCondition ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
2014-06-18 05:51:23 +02:00
std : : stack < const Token * > scopeEnd ;
2014-06-15 16:47:01 +02:00
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
const Token * vartok , * numtok ;
2014-06-16 16:39:41 +02:00
2014-06-18 05:51:23 +02:00
if ( tok - > str ( ) = = " { " ) {
scopeEnd . push ( tok - > link ( ) ) ;
continue ;
}
else if ( tok - > str ( ) = = " } " & & ! scopeEnd . empty ( ) ) {
scopeEnd . pop ( ) ;
continue ;
}
2014-06-16 16:39:41 +02:00
// Comparison
2014-06-18 05:51:23 +02:00
else if ( Token : : Match ( tok , " ==|!=|>=|<= " ) ) {
2014-06-16 16:39:41 +02:00
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
continue ;
if ( tok - > astOperand1 ( ) - > isName ( ) ) {
vartok = tok - > astOperand1 ( ) ;
numtok = tok - > astOperand2 ( ) ;
} else {
vartok = tok - > astOperand2 ( ) ;
numtok = tok - > astOperand1 ( ) ;
}
2014-06-25 06:17:44 +02:00
if ( ! vartok - > isName ( ) | | ! numtok - > isNumber ( ) | | ! MathLib : : isInt ( numtok - > str ( ) ) )
2014-06-16 16:39:41 +02:00
continue ;
} else if ( tok - > str ( ) = = " ! " ) {
2014-06-15 16:47:01 +02:00
vartok = tok - > astOperand1 ( ) ;
2014-06-16 16:39:41 +02:00
numtok = nullptr ;
if ( ! vartok | | ! vartok - > isName ( ) )
continue ;
2014-06-18 06:57:48 +02:00
} else if ( tok - > isName ( ) & &
( Token : : Match ( tok - > astParent ( ) , " %oror%|&& " ) | |
Token : : Match ( tok - > tokAt ( - 2 ) , " if|while ( %var% ) " ) ) ) {
vartok = tok ;
numtok = nullptr ;
2014-06-15 16:47:01 +02:00
} else {
continue ;
2014-06-16 16:39:41 +02:00
}
2014-06-18 06:57:48 +02:00
2014-06-15 16:47:01 +02:00
const unsigned int varid = vartok - > varId ( ) ;
if ( varid = = 0U )
continue ;
const Variable * var = vartok - > variable ( ) ;
if ( ! var | | ! ( var - > isLocal ( ) | | var - > isArgument ( ) ) )
continue ;
2014-06-16 16:39:41 +02:00
std : : list < ValueFlow : : Value > values ;
values . push_back ( ValueFlow : : Value ( tok , numtok ? MathLib : : toLongNumber ( numtok - > str ( ) ) : 0LL ) ) ;
2014-06-15 16:47:01 +02:00
2014-06-19 17:29:41 +02:00
if ( Token : : Match ( tok - > astParent ( ) , " %oror%|&& " ) ) {
Token * parent = const_cast < Token * > ( tok - > astParent ( ) ) ;
const std : : string & op ( parent - > str ( ) ) ;
if ( parent - > astOperand1 ( ) = = tok & &
( ( op = = " && " & & Token : : Match ( tok , " ==|>=|<=|! " ) ) | |
( op = = " || " & & Token : : Match ( tok , " %var%|!= " ) ) ) ) {
bool assign = false ;
for ( ; ! assign & & parent & & parent - > str ( ) = = op ; parent = const_cast < Token * > ( parent - > astParent ( ) ) ) {
std : : stack < Token * > tokens ;
tokens . push ( const_cast < Token * > ( parent - > astOperand2 ( ) ) ) ;
while ( ! tokens . empty ( ) ) {
Token * rhstok = tokens . top ( ) ;
tokens . pop ( ) ;
if ( ! rhstok )
continue ;
tokens . push ( const_cast < Token * > ( rhstok - > astOperand1 ( ) ) ) ;
tokens . push ( const_cast < Token * > ( rhstok - > astOperand2 ( ) ) ) ;
if ( rhstok - > varId ( ) = = varid )
setTokenValue ( rhstok , values . front ( ) ) ;
if ( Token : : Match ( rhstok , " ++|--|= " ) & & Token : : Match ( rhstok - > astOperand1 ( ) , " %varid% " , varid ) ) {
assign = true ;
break ;
}
}
while ( parent - > astParent ( ) & & parent = = parent - > astParent ( ) - > astOperand2 ( ) )
parent = const_cast < Token * > ( parent - > astParent ( ) ) ;
}
}
}
2014-06-15 16:47:01 +02:00
const Token * top = tok - > astTop ( ) ;
2014-06-18 05:51:23 +02:00
if ( top & & Token : : Match ( top - > previous ( ) , " if|while ( " ) & & ! top - > previous ( ) - > isExpandedMacro ( ) ) {
2014-06-16 16:39:41 +02:00
// does condition reassign variable?
2014-06-19 05:41:19 +02:00
if ( isVariableChanged ( top , top - > link ( ) , varid ) ) {
2014-06-16 16:39:41 +02:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " assignment in condition " ) ;
continue ;
}
2014-06-15 16:47:01 +02:00
Token * startToken = nullptr ;
2014-06-16 16:39:41 +02:00
if ( Token : : Match ( tok , " ==|>=|<=|! " ) & & Token : : simpleMatch ( top - > link ( ) , " ) { " ) )
2014-06-15 16:47:01 +02:00
startToken = top - > link ( ) - > next ( ) ;
2014-06-18 06:57:48 +02:00
else if ( Token : : Match ( tok , " %var%|!= " ) & & Token : : simpleMatch ( top - > link ( ) - > linkAt ( 1 ) , " } else { " ))
2014-06-15 16:47:01 +02:00
startToken = top - > link ( ) - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2014-06-18 05:51:23 +02:00
bool ok = true ;
2014-06-15 16:47:01 +02:00
if ( startToken )
2014-06-18 06:57:48 +02:00
ok = valueFlowForward ( startToken - > next ( ) , startToken - > link ( ) , var , varid , values , true , tokenlist , errorLogger , settings ) ;
2014-06-18 05:51:23 +02:00
// After conditional code..
if ( ok & & ! scopeEnd . empty ( ) & & Token : : simpleMatch ( top - > link ( ) , " ) { " ) ) {
Token * after = top - > link ( ) - > linkAt ( 1 ) ;
2014-06-22 19:13:15 +02:00
std : : string unknownFunction ;
if ( settings - > library . isScopeNoReturn ( after , & unknownFunction ) ) {
if ( settings - > debugwarnings & & ! unknownFunction . empty ( ) )
bailout ( tokenlist , errorLogger , after , " possible noreturn scope " ) ;
continue ;
2014-06-18 05:51:23 +02:00
}
if ( Token : : simpleMatch ( after , " } else { " ) ) {
after = after - > linkAt ( 2 ) ;
if ( Token : : simpleMatch ( after - > tokAt ( - 2 ) , " ) ; } " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , after , " possible noreturn scope " ) ;
continue ;
}
}
valueFlowForward ( after - > next ( ) , scopeEnd . top ( ) , var , varid , values , true , tokenlist , errorLogger , settings ) ;
}
2014-01-21 21:13:49 +01:00
}
}
}
2014-03-17 18:43:47 +01:00
static void execute ( const Token * expr ,
std : : map < unsigned int , MathLib : : bigint > * const programMemory ,
MathLib : : bigint * result ,
bool * error )
2014-01-07 19:20:56 +01:00
{
2014-03-17 18:43:47 +01:00
if ( ! expr )
* error = true ;
else if ( expr - > isNumber ( ) )
* result = MathLib : : toLongNumber ( expr - > str ( ) ) ;
else if ( expr - > varId ( ) > 0 ) {
const std : : map < unsigned int , MathLib : : bigint > : : const_iterator var = programMemory - > find ( expr - > varId ( ) ) ;
if ( var = = programMemory - > end ( ) )
* error = true ;
else
* result = var - > second ;
}
2014-01-07 19:20:56 +01:00
2014-03-17 18:43:47 +01:00
else if ( expr - > isComparisonOp ( ) ) {
2014-03-30 10:22:06 +02:00
MathLib : : bigint result1 ( 0 ) , result2 ( 0 ) ;
2014-03-17 18:43:47 +01:00
execute ( expr - > astOperand1 ( ) , programMemory , & result1 , error ) ;
execute ( expr - > astOperand2 ( ) , programMemory , & result2 , error ) ;
if ( expr - > str ( ) = = " < " )
* result = result1 < result2 ;
else if ( expr - > str ( ) = = " <= " )
* result = result1 < = result2 ;
else if ( expr - > str ( ) = = " > " )
* result = result1 > result2 ;
else if ( expr - > str ( ) = = " >= " )
* result = result1 > = result2 ;
else if ( expr - > str ( ) = = " == " )
* result = result1 = = result2 ;
else if ( expr - > str ( ) = = " != " )
* result = result1 ! = result2 ;
}
else if ( expr - > str ( ) = = " = " ) {
execute ( expr - > astOperand2 ( ) , programMemory , result , error ) ;
2014-04-28 15:54:54 +02:00
if ( ! * error & & expr - > astOperand1 ( ) & & expr - > astOperand1 ( ) - > varId ( ) )
2014-03-17 18:43:47 +01:00
( * programMemory ) [ expr - > astOperand1 ( ) - > varId ( ) ] = * result ;
else
* error = true ;
}
2014-03-24 00:16:02 +01:00
else if ( expr - > str ( ) = = " ++ " | | expr - > str ( ) = = " -- " ) {
2014-03-17 18:43:47 +01:00
if ( ! expr - > astOperand1 ( ) | | expr - > astOperand1 ( ) - > varId ( ) = = 0U )
* error = true ;
else {
std : : map < unsigned int , MathLib : : bigint > : : iterator var = programMemory - > find ( expr - > astOperand1 ( ) - > varId ( ) ) ;
if ( var = = programMemory - > end ( ) )
* error = true ;
else {
2014-03-25 18:22:22 +01:00
if ( var - > second = = 0 & &
expr - > str ( ) = = " -- " & &
expr - > astOperand1 ( ) - > variable ( ) & &
expr - > astOperand1 ( ) - > variable ( ) - > typeStartToken ( ) - > isUnsigned ( ) )
* error = true ; // overflow
2014-03-24 00:16:02 +01:00
* result = var - > second + ( expr - > str ( ) = = " ++ " ? 1 : - 1 ) ;
2014-03-17 18:43:47 +01:00
var - > second = * result ;
}
2014-03-16 08:38:52 +01:00
}
2014-03-17 18:43:47 +01:00
}
2014-03-22 19:02:33 +01:00
else if ( expr - > isArithmeticalOp ( ) & & expr - > astOperand1 ( ) & & expr - > astOperand2 ( ) ) {
2014-03-30 10:22:06 +02:00
MathLib : : bigint result1 ( 0 ) , result2 ( 0 ) ;
2014-03-22 19:02:33 +01:00
execute ( expr - > astOperand1 ( ) , programMemory , & result1 , error ) ;
execute ( expr - > astOperand2 ( ) , programMemory , & result2 , error ) ;
if ( expr - > str ( ) = = " + " )
* result = result1 + result2 ;
else if ( expr - > str ( ) = = " - " )
* result = result1 - result2 ;
else if ( expr - > str ( ) = = " * " )
* result = result1 * result2 ;
2014-03-23 20:37:56 +01:00
else if ( result2 = = 0 )
* error = true ;
2014-03-22 19:02:33 +01:00
else if ( expr - > str ( ) = = " / " )
* result = result1 / result2 ;
else if ( expr - > str ( ) = = " % " )
* result = result1 % result2 ;
}
2014-03-17 18:43:47 +01:00
else if ( expr - > str ( ) = = " && " ) {
2014-03-24 06:48:06 +01:00
bool error1 = false ;
execute ( expr - > astOperand1 ( ) , programMemory , result , & error1 ) ;
if ( ! error1 & & * result = = 0 )
2014-03-17 18:43:47 +01:00
* result = 0 ;
else {
2014-03-24 06:48:06 +01:00
bool error2 = false ;
execute ( expr - > astOperand2 ( ) , programMemory , result , & error2 ) ;
if ( error1 & & error2 )
* error = true ;
if ( error2 )
2014-03-17 18:43:47 +01:00
* result = 1 ;
2014-03-24 06:48:06 +01:00
else
* result = ! ! * result ;
2014-01-07 19:20:56 +01:00
}
2014-03-17 18:43:47 +01:00
}
2014-01-07 19:20:56 +01:00
2014-03-17 18:43:47 +01:00
else if ( expr - > str ( ) = = " || " ) {
execute ( expr - > astOperand1 ( ) , programMemory , result , error ) ;
if ( * result = = 0 & & * error = = false )
execute ( expr - > astOperand2 ( ) , programMemory , result , error ) ;
}
2014-01-07 19:20:56 +01:00
2014-03-17 18:43:47 +01:00
else
* error = true ;
}
static bool valueFlowForLoop1 ( const Token * tok , unsigned int * const varid , MathLib : : bigint * const num1 , MathLib : : bigint * const num2 )
{
tok = tok - > tokAt ( 2 ) ;
2014-03-29 20:20:22 +01:00
if ( ! Token : : Match ( tok , " %type%| %var% = " ) )
2014-03-17 18:43:47 +01:00
return false ;
const Token * const vartok = tok - > tokAt ( Token : : Match ( tok , " %var% = " ) ? 0 : 1 ) ;
if ( vartok - > varId ( ) = = 0U )
return false ;
* varid = vartok - > varId ( ) ;
2014-03-29 20:20:22 +01:00
const Token * const num1tok = Token : : Match ( vartok - > tokAt ( 2 ) , " %num% ; " ) ? vartok - > tokAt ( 2 ) : nullptr ;
if ( num1tok )
* num1 = MathLib : : toLongNumber ( num1tok - > str ( ) ) ;
tok = vartok - > tokAt ( 2 ) ;
while ( Token : : Match ( tok , " %var%|%num%|%or%|+|-|*|/|&|[|]|( " ) )
tok = ( tok - > str ( ) = = " ( " ) ? tok - > link ( ) - > next ( ) : tok - > next ( ) ;
if ( ! tok | | tok - > str ( ) ! = " ; " )
return false ;
tok = tok - > next ( ) ;
2014-03-17 18:43:47 +01:00
const Token * num2tok = nullptr ;
if ( Token : : Match ( tok , " %varid% <|<=|!= " , vartok - > varId ( ) ) ) {
tok = tok - > next ( ) ;
num2tok = tok - > astOperand2 ( ) ;
if ( num2tok & & num2tok - > str ( ) = = " ( " & & ! num2tok - > astOperand2 ( ) )
num2tok = num2tok - > astOperand1 ( ) ;
if ( ! Token : : Match ( num2tok , " %num% " ) )
num2tok = 0 ;
}
if ( ! num2tok )
return false ;
2014-04-14 22:46:51 +02:00
* num2 = MathLib : : toLongNumber ( num2tok - > str ( ) ) - ( ( tok - > str ( ) = = " <= " ) ? 0 : 1 ) ;
2014-03-29 20:20:22 +01:00
if ( ! num1tok )
* num1 = * num2 ;
2014-03-17 18:43:47 +01:00
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
2014-05-19 14:37:54 +02:00
if ( ! Token : : Match ( tok , " ; %varid% ++ ) { " , vartok - > varId ( ) ) )
2014-03-17 18:43:47 +01:00
return false ;
return true ;
}
static bool valueFlowForLoop2 ( const Token * tok ,
std : : map < unsigned int , MathLib : : bigint > * memory1 ,
std : : map < unsigned int , MathLib : : bigint > * memory2 )
{
const Token * firstExpression = tok - > next ( ) - > astOperand2 ( ) - > astOperand1 ( ) ;
const Token * secondExpression = tok - > next ( ) - > astOperand2 ( ) - > astOperand2 ( ) - > astOperand1 ( ) ;
const Token * thirdExpression = tok - > next ( ) - > astOperand2 ( ) - > astOperand2 ( ) - > astOperand2 ( ) ;
std : : map < unsigned int , MathLib : : bigint > programMemory ;
2014-03-30 10:22:06 +02:00
MathLib : : bigint result ( 0 ) ;
2014-03-17 18:43:47 +01:00
bool error = false ;
execute ( firstExpression , & programMemory , & result , & error ) ;
if ( error )
return false ;
execute ( secondExpression , & programMemory , & result , & error ) ;
2014-03-24 00:16:02 +01:00
2014-03-17 18:43:47 +01:00
std : : map < unsigned int , MathLib : : bigint > startMemory ( programMemory ) ;
std : : map < unsigned int , MathLib : : bigint > endMemory ;
unsigned int maxcount = 10000 ;
while ( result ! = 0 & & ! error & & - - maxcount ) {
endMemory = programMemory ;
execute ( thirdExpression , & programMemory , & result , & error ) ;
if ( ! error )
execute ( secondExpression , & programMemory , & result , & error ) ;
}
memory1 - > swap ( startMemory ) ;
2014-03-24 00:16:02 +01:00
if ( ! error )
memory2 - > swap ( endMemory ) ;
2014-03-17 18:43:47 +01:00
2014-03-24 00:16:02 +01:00
return true ;
2014-03-17 18:43:47 +01:00
}
static void valueFlowForLoopSimplify ( Token * const bodyStart , const unsigned int varid , const MathLib : : bigint value , TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
const Token * const bodyEnd = bodyStart - > link ( ) ;
// Is variable modified inside for loop
2014-04-20 14:21:43 +02:00
if ( isVariableChanged ( bodyStart , bodyEnd , varid ) )
2014-03-17 18:43:47 +01:00
return ;
for ( Token * tok2 = bodyStart - > next ( ) ; tok2 ! = bodyEnd ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) = = varid ) {
const Token * parent = tok2 - > astParent ( ) ;
while ( parent ) {
const Token * const p = parent ;
parent = parent - > astParent ( ) ;
2014-03-25 18:22:22 +01:00
if ( parent & & parent - > str ( ) = = " : " )
2014-03-17 18:43:47 +01:00
break ;
2014-03-25 18:22:22 +01:00
if ( parent & & parent - > str ( ) = = " ? " ) {
if ( parent - > astOperand2 ( ) ! = p )
parent = NULL ;
break ;
}
2014-03-15 11:29:33 +01:00
}
2014-03-17 18:43:47 +01:00
if ( parent ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " For loop variable " + tok2 - > str ( ) + " stopping on ? " ) ;
continue ;
}
ValueFlow : : Value value1 ( value ) ;
value1 . varId = tok2 - > varId ( ) ;
setTokenValue ( tok2 , value1 ) ;
2014-03-16 08:38:52 +01:00
}
2014-01-07 19:20:56 +01:00
2014-05-19 21:44:00 +02:00
else if ( Token : : simpleMatch ( tok2 , " ) { " ) && Token::findmatch(tok2->link(), " % varid % " , tok2, varid)) {
2014-03-25 21:40:36 +01:00
if ( Token : : findmatch ( tok2 , " continue|break|return " , tok2 - > linkAt ( 1 ) , varid ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " For loop variable bailout on conditional continue|break|return " ) ;
break ;
}
2014-03-17 18:43:47 +01:00
if ( settings - > debugwarnings )
2014-03-25 21:40:36 +01:00
bailout ( tokenlist , errorLogger , tok2 , " For loop variable skipping conditional scope " ) ;
tok2 = tok2 - > next ( ) - > link ( ) ;
2014-05-19 21:44:00 +02:00
if ( Token : : simpleMatch ( tok2 , " } else { " ) ) {
2014-03-25 21:40:36 +01:00
if ( Token : : findmatch ( tok2 , " continue|break|return " , tok2 - > linkAt ( 2 ) , varid ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " For loop variable bailout on conditional continue|break|return " ) ;
break ;
}
tok2 = tok2 - > linkAt ( 2 ) ;
}
2014-03-17 18:43:47 +01:00
}
}
}
static void valueFlowForLoop ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( ! Token : : simpleMatch ( tok , " for ( " ) | |
! Token : : simpleMatch ( tok - > next ( ) - > astOperand2 ( ) , " ; " ) | |
! Token : : simpleMatch ( tok - > next ( ) - > astOperand2 ( ) - > astOperand2 ( ) , " ; " ) )
continue ;
2014-03-16 08:38:52 +01:00
2014-03-17 18:43:47 +01:00
Token * const bodyStart = tok - > linkAt ( 1 ) - > next ( ) ;
2014-03-16 08:38:52 +01:00
2014-03-30 10:22:06 +02:00
unsigned int varid ( 0 ) ;
MathLib : : bigint num1 ( 0 ) , num2 ( 0 ) ;
2014-03-16 08:38:52 +01:00
2014-03-17 18:43:47 +01:00
if ( valueFlowForLoop1 ( tok , & varid , & num1 , & num2 ) ) {
valueFlowForLoopSimplify ( bodyStart , varid , num1 , tokenlist , errorLogger , settings ) ;
valueFlowForLoopSimplify ( bodyStart , varid , num2 , tokenlist , errorLogger , settings ) ;
} else {
std : : map < unsigned int , MathLib : : bigint > mem1 , mem2 ;
if ( valueFlowForLoop2 ( tok , & mem1 , & mem2 ) ) {
std : : map < unsigned int , MathLib : : bigint > : : const_iterator it ;
for ( it = mem1 . begin ( ) ; it ! = mem1 . end ( ) ; + + it )
valueFlowForLoopSimplify ( bodyStart , it - > first , it - > second , tokenlist , errorLogger , settings ) ;
for ( it = mem2 . begin ( ) ; it ! = mem2 . end ( ) ; + + it )
valueFlowForLoopSimplify ( bodyStart , it - > first , it - > second , tokenlist , errorLogger , settings ) ;
2014-01-07 19:20:56 +01:00
}
}
}
}
2014-01-06 16:37:52 +01:00
static void valueFlowSubFunction ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
std : : list < ValueFlow : : Value > argvalues ;
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
2014-01-08 16:17:47 +01:00
if ( ! Token : : Match ( tok , " [(,] " ) )
continue ;
2014-01-08 06:04:51 +01:00
// passing value(s) to function
2014-01-06 16:37:52 +01:00
if ( Token : : Match ( tok , " [(,] %var% [,)] " ) & & ! tok - > next ( ) - > values . empty ( ) )
argvalues = tok - > next ( ) - > values ;
else if ( Token : : Match ( tok , " [(,] %num% [,) ] " )) {
argvalues . clear ( ) ;
2014-01-07 19:20:56 +01:00
argvalues . push_back ( ValueFlow : : Value ( MathLib : : toLongNumber ( tok - > next ( ) - > str ( ) ) ) ) ;
2014-01-06 16:37:52 +01:00
} else {
2014-01-08 16:17:47 +01:00
// bool operator => values 1/0 are passed to function..
const Token * op = tok - > next ( ) ;
while ( op & & op - > astParent ( ) & & ! Token : : Match ( op - > astParent ( ) , " [(,] " ) )
op = op - > astParent ( ) ;
2014-01-08 16:49:15 +01:00
if ( Token : : Match ( op , " %comp%|%oror%|&&|! " ) ) {
2014-01-08 16:17:47 +01:00
argvalues . clear ( ) ;
argvalues . push_back ( ValueFlow : : Value ( 0 ) ) ;
argvalues . push_back ( ValueFlow : : Value ( 1 ) ) ;
} else {
// possible values are unknown..
continue ;
}
2014-01-06 16:37:52 +01:00
}
const Token * const argumentToken = tok - > next ( ) ;
// is this a function call?
const Token * ftok = tok ;
while ( ftok & & ftok - > str ( ) ! = " ( " )
ftok = ftok - > astParent ( ) ;
if ( ! ftok | | ! ftok - > astOperand1 ( ) | | ! ftok - > astOperand2 ( ) | | ! ftok - > astOperand1 ( ) - > function ( ) )
continue ;
// Get argument nr
unsigned int argnr = 0 ;
for ( const Token * argtok = ftok - > next ( ) ; argtok & & argtok ! = argumentToken ; argtok = argtok - > nextArgument ( ) )
+ + argnr ;
// Get function argument, and check if parameter is passed by value
const Function * const function = ftok - > astOperand1 ( ) - > function ( ) ;
2014-02-16 10:32:10 +01:00
const Variable * const arg = function ? function - > getArgumentVar ( argnr ) : nullptr ;
if ( ! Token : : Match ( arg ? arg - > typeStartToken ( ) : nullptr , " %type% %var% ,|) " ) )
2014-01-06 16:37:52 +01:00
continue ;
// Function scope..
2014-02-16 10:32:10 +01:00
const Scope * const functionScope = function ? function - > functionScope : nullptr ;
2014-01-06 16:37:52 +01:00
if ( ! functionScope )
continue ;
// Set value in function scope..
const unsigned int varid2 = arg - > nameToken ( ) - > varId ( ) ;
for ( const Token * tok2 = functionScope - > classStart - > next ( ) ; tok2 ! = functionScope - > classEnd ; tok2 = tok2 - > next ( ) ) {
2014-01-11 07:52:25 +01:00
if ( Token : : Match ( tok2 , " %varid% !!= " , varid2 ) ) {
2014-06-13 16:34:57 +02:00
for ( std : : list < ValueFlow : : Value > : : const_iterator val = argvalues . begin ( ) ; val ! = argvalues . end ( ) ; + + val )
setTokenValue ( const_cast < Token * > ( tok2 ) , * val ) ;
2014-06-24 19:30:46 +02:00
} else if ( tok2 - > str ( ) = = " { " || tok2->str() == " ? " ) {
2014-01-06 16:37:52 +01:00
if ( settings - > debugwarnings )
2014-06-24 19:30:46 +02:00
bailout ( tokenlist , errorLogger , tok2 , " parameter " + arg - > nameToken ( ) - > str ( ) + " , at ' " + tok2 - > str ( ) + " ' " ) ;
2014-01-08 06:04:51 +01:00
break ;
2014-01-06 16:37:52 +01:00
}
}
}
}
2014-01-05 20:06:46 +01:00
void ValueFlow : : setValues ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
2014-01-04 20:57:02 +01:00
{
2014-01-05 20:06:46 +01:00
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) )
2014-01-04 20:57:02 +01:00
tok - > values . clear ( ) ;
2014-01-18 19:30:44 +01:00
valueFlowNumber ( tokenlist ) ;
2014-04-14 06:45:39 +02:00
valueFlowBitAnd ( tokenlist ) ;
2014-01-07 19:20:56 +01:00
valueFlowForLoop ( tokenlist , errorLogger , settings ) ;
2014-01-05 20:06:46 +01:00
valueFlowBeforeCondition ( tokenlist , errorLogger , settings ) ;
2014-01-21 21:13:49 +01:00
valueFlowAfterAssign ( tokenlist , errorLogger , settings ) ;
2014-06-15 16:47:01 +02:00
valueFlowAfterCondition ( tokenlist , errorLogger , settings ) ;
2014-01-06 16:37:52 +01:00
valueFlowSubFunction ( tokenlist , errorLogger , settings ) ;
2014-01-04 20:57:02 +01:00
}