2014-01-04 20:57:02 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
* Copyright ( C ) 2007 - 2013 Daniel Marjamäki and Cppcheck team .
*
* 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-01-06 16:37:52 +01:00
# include <iostream>
2014-01-19 09:05:48 +01:00
# include <stack>
2014-01-06 16:37:52 +01: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 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-01-13 05:52:28 +01:00
const bool addressOf = tok & & Token : : Match ( 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 ;
// 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 ( ) ;
}
tok = tok ? tok - > previous ( ) : NULL ;
if ( ! Token : : Match ( tok , " %var% ( " ) )
return false ; // not a function => dont bailout
2014-01-12 18:19:00 +01:00
if ( ! tok - > function ( ) ) {
2014-01-12 19:48:20 +01:00
// if value is 0 and the library says 0 is invalid => dont bailout
if ( value . intvalue = = 0 & & settings - > library . isnullargbad ( tok - > str ( ) , 1 + argnr ) )
return false ;
// inconclusive => don't bailout
2014-01-13 05:52:28 +01:00
if ( inconclusive & & ! addressOf & & settings - > inconclusive ) {
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-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-01-19 09:05:48 +01:00
return NULL ;
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-01-11 20:53:23 +01:00
if ( parent ! = NULL & &
parent - > astOperand2 ( ) = = op & &
parent - > astOperand1 ( ) ! = NULL & &
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-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-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-01-04 20:57:02 +01:00
unsigned int varid ;
MathLib : : bigint num ;
2014-01-05 20:06:46 +01:00
const Variable * var ;
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 ( " ) ) {
const Token * start = tok2 - > link ( ) - > next ( ) ;
const Token * end = start - > link ( ) ;
2014-01-25 09:22:32 +01:00
if ( tok2 - > astOperand2 ( ) - > str ( ) = = " ; " & &
tok2 - > astOperand2 ( ) - > astOperand2 ( ) & &
tok2 - > astOperand2 ( ) - > astOperand2 ( ) - > str ( ) = = " ; " )
start = tok2 - > astOperand2 ( ) - > astOperand2 ( ) ;
if ( Token : : findmatch ( start , " ++|-- %varid% " , end , varid ) | |
Token : : findmatch ( start , " %varid% ++|--|= " , 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-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-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 ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " stopping on } " ) ;
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 ( ) & &
( Token : : Match ( 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 ( ) ;
if ( Token : : findmatch ( start , " ++|--| %varid% ++|--|= " , end , varid ) ) {
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 ;
if ( Token : : Match ( tok2 - > previous ( ) , " ) { " ) & &
! 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-13 16:07:25 +01:00
// goto label
if ( Token : : Match ( tok2 , " [;{}] %var% : " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " stopping on goto label " ) ;
break ;
}
2014-01-04 20:57:02 +01:00
}
}
}
2014-01-21 21:13:49 +01:00
static void valueFlowAfterAssign ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
2014-01-21 21:17:03 +01:00
// temporarily hide compiler warnings
( void ) errorLogger ;
( void ) settings ;
2014-01-21 21:13:49 +01:00
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-01-22 20:16:31 +01:00
unsigned int number_of_if = 0 ;
for ( Token * tok2 = tok ; tok2 & & tok2 ! = endToken ; tok2 = tok2 - > next ( ) ) {
2014-01-22 06:38:25 +01:00
if ( Token : : Match ( tok2 , " sizeof|typeof|typeid ( " ) )
2014-01-21 21:13:49 +01:00
tok2 = tok2 - > linkAt ( 1 ) ;
2014-01-22 20:16:31 +01:00
// conditional block of code that assigns variable..
if ( Token : : Match ( tok2 , " %var% ( " ) & & Token : : Match ( tok2 - > linkAt ( 1 ) , " ) { " ) ) {
Token * const start = tok2 - > linkAt ( 1 ) - > next ( ) ;
Token * const end = start - > link ( ) ;
// TODO: don't check noreturn scopes
if ( number_of_if > 0U & & Token : : findmatch ( start , " %varid% " , end , varid ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " is assigned in conditional code " ) ;
break ;
}
2014-01-24 18:22:38 +01:00
if ( Token : : findmatch ( start , " ++|-- %varid% " , end , varid ) | |
Token : : findmatch ( start , " %varid% ++|--|= " , end , varid ) ) {
2014-01-22 20:16:31 +01:00
if ( number_of_if = = 0 & &
Token : : simpleMatch ( tok2 , " if ( " ) & &
! ( Token : : simpleMatch ( end , " } else { " ) & &
( Token : : findmatch ( end , " %varid% " , end - > linkAt ( 2 ) , varid ) | |
Token : : findmatch ( end , " return|continue|break " , end - > linkAt ( 2 ) ) ) ) ) {
+ + number_of_if ;
tok2 = end ;
} else {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " variable " + var - > nameToken ( ) - > str ( ) + " is assigned in conditional code " ) ;
break ;
}
}
}
else if ( tok2 - > str ( ) = = " } " )
+ + number_of_if ;
2014-01-21 21:13:49 +01:00
if ( tok2 - > varId ( ) = = varid ) {
2014-01-22 06:38:25 +01:00
// bailout: assignment
if ( Token : : Match ( tok2 - > previous ( ) , " !!* %var% = " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " assignment of " + tok2 - > str ( ) ) ;
2014-01-21 21:13:49 +01:00
break ;
2014-01-22 06:38:25 +01:00
}
2014-01-24 18:22:38 +01:00
// bailout increment/decrement for now..
if ( Token : : Match ( tok2 - > previous ( ) , " ++|-- %var% " ) | | Token : : Match ( tok , " %var% ++|-- " ) ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " increment/decrement of " + tok2 - > str ( ) ) ;
break ;
}
2014-01-22 20:16:31 +01: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 ;
}
2014-01-22 06:38:25 +01:00
{
std : : list < ValueFlow : : Value > : : const_iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
setTokenValue ( tok2 , * it ) ;
}
2014-01-21 21:13:49 +01:00
2014-01-22 06:38:25 +01:00
// 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 " ) ;
break ;
}
if ( inconclusive ) {
std : : list < ValueFlow : : Value > : : iterator it ;
for ( it = values . begin ( ) ; it ! = values . end ( ) ; + + it )
it - > inconclusive = true ;
}
2014-01-21 21:13:49 +01:00
}
}
}
}
2014-01-07 19:20:56 +01:00
static void valueFlowForLoop ( TokenList * tokenlist , ErrorLogger * errorLogger , const Settings * settings )
{
for ( Token * tok = tokenlist - > front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( ! Token : : Match ( tok , " for ( " ) )
continue ;
tok = tok - > tokAt ( 2 ) ;
if ( ! Token : : Match ( tok , " %type%| %var% = %num% ; " ) ) { // TODO: don't use %num%
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " For loop not handled " ) ;
continue ;
}
Token * const vartok = tok - > tokAt ( Token : : Match ( tok , " %var% = " ) ? 0 : 1 ) ;
const MathLib : : bigint num1 = MathLib : : toLongNumber ( vartok - > strAt ( 2 ) ) ;
if ( vartok - > varId ( ) = = 0U )
continue ;
tok = vartok - > tokAt ( 4 ) ;
2014-01-10 18:18:49 +01:00
const Token * num2tok = 0 ;
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 ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " For loop not handled " ) ;
continue ;
}
const MathLib : : bigint num2 = MathLib : : toLongNumber ( num2tok ? num2tok - > str ( ) : " 0 " ) - ( ( tok - > str ( ) = = " <= " ) ? 0 : 1 ) ;
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
if ( ! num2tok | | ! Token : : Match ( tok , " ; %varid% ++ ) { " , vartok - > varId ( ) ) ) {
2014-01-07 19:20:56 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok , " For loop not handled " ) ;
continue ;
}
2014-01-10 18:18:49 +01:00
Token * const bodyStart = tok - > tokAt ( 4 ) ;
2014-01-07 19:20:56 +01:00
const Token * const bodyEnd = bodyStart - > link ( ) ;
// Is variable modified inside for loop
bool modified = false ;
for ( const Token * tok2 = bodyStart - > next ( ) ; tok2 ! = bodyEnd ; tok2 = tok2 - > next ( ) ) {
if ( Token : : Match ( tok2 , " %varid% = " , vartok - > varId ( ) ) ) {
modified = true ;
break ;
}
}
if ( modified )
continue ;
for ( Token * tok2 = bodyStart - > next ( ) ; tok2 ! = bodyEnd ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) = = vartok - > varId ( ) ) {
2014-01-18 19:30:44 +01:00
ValueFlow : : Value value1 ( num1 ) ;
value1 . varId = tok2 - > varId ( ) ;
setTokenValue ( tok2 , value1 ) ;
ValueFlow : : Value value2 ( num2 ) ;
value2 . varId = tok2 - > varId ( ) ;
setTokenValue ( tok2 , value2 ) ;
2014-01-07 19:20:56 +01:00
}
if ( tok2 - > str ( ) = = " { " ) {
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " For loop variable " + vartok - > str ( ) + " stopping on { " ) ;
break ;
}
}
}
}
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 ( ) ;
const Variable * const arg = function ? function - > getArgumentVar ( argnr ) : NULL ;
if ( ! Token : : Match ( arg ? arg - > typeStartToken ( ) : NULL , " const| %type% %var% ,|) " ) )
continue ;
// Function scope..
const Scope * const functionScope = function ? function - > functionScope : NULL ;
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-01-06 16:37:52 +01:00
std : : list < ValueFlow : : Value > & values = const_cast < Token * > ( tok2 ) - > values ;
values . insert ( values . begin ( ) , argvalues . begin ( ) , argvalues . end ( ) ) ;
2014-01-11 07:52:25 +01:00
} else if ( tok2 - > str ( ) = = " { " ) {
2014-01-06 16:37:52 +01:00
if ( settings - > debugwarnings )
bailout ( tokenlist , errorLogger , tok2 , " parameter " + arg - > nameToken ( ) - > 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-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-01-06 16:37:52 +01:00
valueFlowSubFunction ( tokenlist , errorLogger , settings ) ;
2014-01-04 20:57:02 +01:00
}