2014-01-04 20:57:02 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2019-02-09 07:24:06 +01:00
* Copyright ( C ) 2007 - 2019 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/>.
*/
2017-05-27 04:33:47 +02:00
# include "library.h"
# include "platform.h"
# include "settings.h"
2014-01-04 20:57:02 +01:00
# include "testsuite.h"
# include "token.h"
2017-05-27 04:33:47 +02:00
# include "tokenize.h"
# include "valueflow.h"
2014-01-04 20:57:02 +01:00
2017-05-18 21:52:31 +02:00
# include <simplecpp.h>
2016-11-13 22:59:56 +01:00
# include <cmath>
2017-05-27 04:33:47 +02:00
# include <list>
# include <map>
# include <ostream>
# include <string>
# include <utility>
# include <vector>
2019-03-13 21:44:26 +01:00
# include <cstdint>
2015-03-11 22:26:33 +01:00
2014-01-04 20:57:02 +01:00
class TestValueFlow : public TestFixture {
public :
2014-11-20 14:20:09 +01:00
TestValueFlow ( ) : TestFixture ( " TestValueFlow " ) {
2014-01-04 20:57:02 +01:00
}
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2014-01-04 20:57:02 +01:00
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2018-02-11 22:14:44 +01:00
// strcpy, abort cfg
2015-10-07 18:33:57 +02:00
const char cfg [ ] = " <?xml version= \" 1.0 \" ?> \n "
2019-01-12 21:51:39 +01:00
" <def> \n "
" <function name= \" strcpy \" > <arg nr= \" 1 \" ><not-null/></arg> </function> \n "
" <function name= \" abort \" > <noreturn>true</noreturn> </function> \n " // abort is a noreturn function
" </def> " ;
2015-10-07 18:33:57 +02:00
settings . library . loadxmldata ( cfg , sizeof ( cfg ) ) ;
2019-09-20 15:06:37 +02:00
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
2015-10-07 18:33:57 +02:00
2014-01-18 19:30:44 +01:00
TEST_CASE ( valueFlowNumber ) ;
2014-08-03 20:11:22 +02:00
TEST_CASE ( valueFlowString ) ;
TEST_CASE ( valueFlowPointerAlias ) ;
2018-11-10 16:40:40 +01:00
TEST_CASE ( valueFlowLifetime ) ;
2015-02-24 15:57:39 +01:00
TEST_CASE ( valueFlowArrayElement ) ;
2016-11-20 15:14:49 +01:00
TEST_CASE ( valueFlowMove ) ;
2014-01-18 19:30:44 +01:00
2014-04-14 06:45:39 +02:00
TEST_CASE ( valueFlowBitAnd ) ;
2018-11-03 23:25:46 +01:00
TEST_CASE ( valueFlowRightShift ) ;
2014-04-14 06:45:39 +02:00
2014-01-18 19:30:44 +01:00
TEST_CASE ( valueFlowCalculations ) ;
2018-03-23 08:28:12 +01:00
TEST_CASE ( valueFlowSizeof ) ;
2014-01-18 19:30:44 +01:00
2017-05-19 14:34:59 +02:00
TEST_CASE ( valueFlowErrorPath ) ;
2014-01-06 10:09:49 +01:00
TEST_CASE ( valueFlowBeforeCondition ) ;
2014-01-18 08:45:24 +01:00
TEST_CASE ( valueFlowBeforeConditionAndAndOrOrGuard ) ;
TEST_CASE ( valueFlowBeforeConditionAssignIncDec ) ;
TEST_CASE ( valueFlowBeforeConditionFunctionCall ) ;
TEST_CASE ( valueFlowBeforeConditionGlobalVariables ) ;
TEST_CASE ( valueFlowBeforeConditionGoto ) ;
TEST_CASE ( valueFlowBeforeConditionIfElse ) ;
TEST_CASE ( valueFlowBeforeConditionLoop ) ;
TEST_CASE ( valueFlowBeforeConditionMacro ) ;
TEST_CASE ( valueFlowBeforeConditionSizeof ) ;
TEST_CASE ( valueFlowBeforeConditionSwitch ) ;
TEST_CASE ( valueFlowBeforeConditionTernaryOp ) ;
2019-10-03 09:58:57 +02:00
TEST_CASE ( valueFlowBeforeConditionForward ) ;
2014-01-18 08:45:24 +01:00
2014-01-21 21:13:49 +01:00
TEST_CASE ( valueFlowAfterAssign ) ;
2014-06-15 16:47:01 +02:00
TEST_CASE ( valueFlowAfterCondition ) ;
2019-09-26 10:32:25 +02:00
TEST_CASE ( valueFlowAfterConditionExpr ) ;
2019-05-29 09:45:15 +02:00
TEST_CASE ( valueFlowAfterConditionSeveralNot ) ;
2017-08-23 11:13:47 +02:00
TEST_CASE ( valueFlowForwardCompoundAssign ) ;
2017-08-27 19:50:44 +02:00
TEST_CASE ( valueFlowForwardCorrelatedVariables ) ;
2018-08-10 18:05:23 +02:00
TEST_CASE ( valueFlowForwardModifiedVariables ) ;
2017-09-20 12:53:25 +02:00
TEST_CASE ( valueFlowForwardFunction ) ;
2018-03-16 19:13:48 +01:00
TEST_CASE ( valueFlowForwardTernary ) ;
2017-08-28 22:39:12 +02:00
TEST_CASE ( valueFlowForwardLambda ) ;
2014-06-15 16:47:01 +02:00
2018-12-31 17:05:46 +01:00
TEST_CASE ( valueFlowFwdAnalysis ) ;
2015-07-20 19:45:38 +02:00
TEST_CASE ( valueFlowSwitchVariable ) ;
2014-01-07 19:20:56 +01:00
TEST_CASE ( valueFlowForLoop ) ;
2019-08-11 15:39:37 +02:00
TEST_CASE ( valueFlowSubFunction ) ;
2014-06-29 18:04:38 +02:00
TEST_CASE ( valueFlowFunctionReturn ) ;
2015-02-03 22:12:05 +01:00
TEST_CASE ( valueFlowFunctionDefaultParameter ) ;
2015-07-16 17:33:16 +02:00
TEST_CASE ( knownValue ) ;
2016-10-26 10:36:02 +02:00
TEST_CASE ( valueFlowSizeofForwardDeclaredEnum ) ;
2017-01-09 15:53:08 +01:00
TEST_CASE ( valueFlowGlobalVar ) ;
2017-03-23 20:01:16 +01:00
2019-04-21 06:54:32 +02:00
TEST_CASE ( valueFlowGlobalConstVar ) ;
2017-09-15 15:58:19 +02:00
TEST_CASE ( valueFlowGlobalStaticVar ) ;
2017-03-23 20:01:16 +01:00
TEST_CASE ( valueFlowInlineAssembly ) ;
2017-04-23 18:05:14 +02:00
2018-12-16 07:35:27 +01:00
TEST_CASE ( valueFlowSameExpression ) ;
2017-04-23 18:05:14 +02:00
TEST_CASE ( valueFlowUninit ) ;
2018-08-10 11:29:16 +02:00
2018-11-07 06:49:07 +01:00
TEST_CASE ( valueFlowTerminatingCond ) ;
2018-08-10 11:29:16 +02:00
TEST_CASE ( valueFlowContainerSize ) ;
2019-06-16 16:02:27 +02:00
TEST_CASE ( valueFlowDynamicBufferSize ) ;
2019-07-10 16:59:05 +02:00
2019-07-24 10:57:19 +02:00
TEST_CASE ( valueFlowSafeFunctionParameterValues ) ;
2019-07-11 16:05:34 +02:00
TEST_CASE ( valueFlowUnknownFunctionReturn ) ;
2019-08-12 12:58:53 +02:00
TEST_CASE ( valueFlowPointerAliasDeref ) ;
Fix crashes in valueflow (#2236)
* Fix crashes in valueflow
http://cppcheck1.osuosl.org:8000/crash.html
For instance in http://cppcheck1.osuosl.org:8000/styx
```
==19651==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000001c (pc 0x556f21abc3df bp 0x7ffc140d2720 sp 0x7ffc140d2710 T0)
==19651==The signal is caused by a READ memory access.
==19651==Hint: address points to the zero page.
#0 0x556f21abc3de in Variable::isGlobal() const ../lib/symboldatabase.h:342
#1 0x556f221f801a in valueFlowForwardVariable ../lib/valueflow.cpp:2471
#2 0x556f22208130 in valueFlowForward ../lib/valueflow.cpp:3204
#3 0x556f221e9e14 in valueFlowReverse ../lib/valueflow.cpp:1892
#4 0x556f221f1a43 in valueFlowBeforeCondition ../lib/valueflow.cpp:2200
#5 0x556f2223dbb5 in ValueFlow::setValues(TokenList*, SymbolDatabase*, ErrorLogger*, Settings const*) ../lib/valueflow.cpp:6521
#6 0x556f220e5991 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/tokenize.cpp:2342
#7 0x556f21d8d066 in CppCheck::checkFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream&) ../lib/cppcheck.cpp:508
#8 0x556f21d84cd3 in CppCheck::check(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/cppcheck.cpp:192
#9 0x556f21a28796 in CppCheckExecutor::check_internal(CppCheck&, int, char const* const*) ../cli/cppcheckexecutor.cpp:884
#10 0x556f21a24be8 in CppCheckExecutor::check(int, char const* const*) ../cli/cppcheckexecutor.cpp:198
#11 0x556f22313063 in main ../cli/main.cpp:95
```
* Add test case for crash in valueflow
2019-10-16 20:54:07 +02:00
TEST_CASE ( valueFlowCrashIncompleteCode ) ;
2019-12-06 08:08:40 +01:00
TEST_CASE ( valueFlowCrash ) ;
2020-03-20 10:37:16 +01:00
TEST_CASE ( valueFlowHang ) ;
2020-01-17 03:17:26 +01:00
TEST_CASE ( valueFlowCrashConstructorInitialization ) ;
2014-01-04 20:57:02 +01:00
}
2019-02-22 06:38:56 +01:00
static bool isNotTokValue ( const ValueFlow : : Value & val ) {
return ! val . isTokValue ( ) ;
}
2018-08-10 18:05:23 +02:00
bool testValueOfXKnown ( const char code [ ] , unsigned int linenr , int value ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2018-08-10 22:06:23 +02:00
for ( const ValueFlow : : Value & val : tok - > values ( ) ) {
if ( val . isKnown ( ) & & val . intvalue = = value )
2018-08-10 18:05:23 +02:00
return true ;
}
}
}
return false ;
}
2014-11-20 14:20:09 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , int value ) {
2014-01-04 20:57:02 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
2019-09-20 15:06:37 +02:00
if ( v . isIntValue ( ) & & ! v . isImpossible ( ) & & v . intvalue = = value )
2014-01-04 20:57:02 +01:00
return true ;
}
}
}
return false ;
}
2017-08-23 11:13:47 +02:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , float value , float diff ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
2019-09-20 15:06:37 +02:00
if ( v . isFloatValue ( ) & & ! v . isImpossible ( ) & & v . floatValue > = value - diff & &
v . floatValue < = value + diff )
2017-08-23 11:13:47 +02:00
return true ;
}
}
}
return false ;
}
2017-05-19 14:34:59 +02:00
std : : string getErrorPathForX ( const char code [ ] , unsigned int linenr ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) ! = " x " | | tok - > linenr ( ) ! = linenr )
continue ;
std : : ostringstream ostr ;
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
for ( const ValueFlow : : Value : : ErrorPathItem & ep : v . errorPath ) {
const Token * eptok = ep . first ;
const std : : string & msg = ep . second ;
2017-05-19 14:34:59 +02:00
ostr < < eptok - > linenr ( ) < < ' , ' < < msg < < ' \n ' ;
}
}
return ostr . str ( ) ;
}
return " " ;
}
2014-01-06 07:44:58 +01:00
2018-11-10 16:40:40 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , const char value [ ] , ValueFlow : : Value : : ValueType type ) {
2014-08-03 20:11:22 +02:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
if ( v . valueType = = type & & Token : : simpleMatch ( v . tokvalue , value ) )
2014-08-03 20:11:22 +02:00
return true ;
}
}
}
return false ;
}
2019-06-16 16:02:27 +02:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , int value , ValueFlow : : Value : : ValueType type ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
if ( v . valueType = = type & & v . intvalue = = value )
return true ;
}
}
}
return false ;
}
2016-11-20 15:14:49 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , ValueFlow : : Value : : MoveKind moveKind ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
if ( v . isMovedValue ( ) & & v . moveKind = = moveKind )
2016-11-20 15:14:49 +01:00
return true ;
}
}
}
return false ;
}
2015-07-29 19:54:57 +02:00
bool testConditionalValueOfX ( const char code [ ] , unsigned int linenr , int value ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
if ( v . isIntValue ( ) & & v . intvalue = = value & & v . condition )
2015-07-29 19:54:57 +02:00
return true ;
}
}
}
return false ;
}
2014-11-20 14:20:09 +01:00
void bailout ( const char code [ ] ) {
2014-01-06 07:44:58 +01:00
settings . debugwarnings = true ;
2017-05-18 21:52:31 +02:00
errout . str ( " " ) ;
2018-04-09 09:41:24 +02:00
std : : vector < std : : string > files ( 1 , " test.cpp " ) ;
2017-05-18 21:52:31 +02:00
std : : istringstream istr ( code ) ;
const simplecpp : : TokenList tokens1 ( istr , files , files [ 0 ] ) ;
simplecpp : : TokenList tokens2 ( files ) ;
std : : map < std : : string , simplecpp : : TokenList * > filedata ;
simplecpp : : preprocess ( tokens2 , tokens1 , files , filedata , simplecpp : : DUI ( ) ) ;
2014-01-06 07:44:58 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
2017-05-18 21:52:31 +02:00
tokenizer . createTokens ( & tokens2 ) ;
tokenizer . simplifyTokens1 ( " " ) ;
2015-10-07 18:33:57 +02:00
settings . debugwarnings = false ;
2014-01-06 07:44:58 +01:00
}
2019-07-10 16:59:05 +02:00
std : : list < ValueFlow : : Value > tokenValues ( const char code [ ] , const char tokstr [ ] , const Settings * s = nullptr ) {
Tokenizer tokenizer ( s ? s : & settings , this ) ;
2014-01-18 19:30:44 +01:00
std : : istringstream istr ( code ) ;
errout . str ( " " ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
const Token * tok = Token : : findmatch ( tokenizer . tokens ( ) , tokstr ) ;
2017-03-27 18:48:34 +02:00
return tok ? tok - > values ( ) : std : : list < ValueFlow : : Value > ( ) ;
2014-01-20 21:45:30 +01:00
}
2014-11-20 14:20:09 +01:00
ValueFlow : : Value valueOfTok ( const char code [ ] , const char tokstr [ ] ) {
2014-01-20 21:45:30 +01:00
std : : list < ValueFlow : : Value > values = tokenValues ( code , tokstr ) ;
2016-11-13 22:59:56 +01:00
return values . size ( ) = = 1U & & ! values . front ( ) . isTokValue ( ) ? values . front ( ) : ValueFlow : : Value ( ) ;
2014-01-18 19:30:44 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowNumber ( ) {
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 123 , valueOfTok ( " x=123; " , " 123 " ) . intvalue ) ;
2019-11-10 08:27:55 +01:00
ASSERT_EQUALS_DOUBLE ( 192.0 , valueOfTok ( " x=0x0.3p10; " , " 0x0.3p10 " ) . floatValue , 1e-5 ) ; // 3 * 16^-1 * 2^10 = 192
2016-11-13 22:59:56 +01:00
ASSERT ( std : : fabs ( valueOfTok ( " x=0.5; " , " 0.5 " ) . floatValue - 0.5f ) < 0.1f ) ;
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 10 , valueOfTok ( " enum {A=10,B=15}; x=A+0; " , " + " ) . intvalue ) ;
2015-11-12 16:38:58 +01:00
ASSERT_EQUALS ( 0 , valueOfTok ( " x=false; " , " false " ) . intvalue ) ;
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 1 , valueOfTok ( " x=true; " , " true " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " x(NULL); " , " NULL " ) . intvalue ) ;
ASSERT_EQUALS ( ( int ) ( ' a ' ) , valueOfTok ( " x='a'; " , " 'a' " ) . intvalue ) ;
2015-11-12 16:38:58 +01:00
ASSERT_EQUALS ( ( int ) ( ' \n ' ) , valueOfTok ( " x=' \\ n'; " , " ' \\ n' " ) . intvalue ) ;
2020-02-19 07:51:39 +01:00
ASSERT_EQUALS ( 0xFFFFFFFF00000000 , valueOfTok ( " x=0xFFFFFFFF00000000; " , " 0xFFFFFFFF00000000 " ) . intvalue ) ; // #7701
2019-10-19 21:08:59 +02:00
// scope
{
const char code [ ] = " namespace N { enum E {e0,e1}; } \n "
" void foo() { x = N::e1; } " ;
ASSERT_EQUALS ( 1 , valueOfTok ( code , " :: " ) . intvalue ) ;
}
2014-01-18 19:30:44 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowString ( ) {
2014-08-03 20:11:22 +02:00
const char * code ;
2014-08-04 12:13:15 +02:00
// valueFlowAfterAssign
2014-08-03 20:11:22 +02:00
code = " const char * f() { \n "
" static const char *x; \n "
" if (a) x = \" 123 \" ; \n "
" return x; \n "
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " \" 123 \" " , ValueFlow : : Value : : TOK ) ) ;
2014-08-04 12:13:15 +02:00
// valueFlowSubFunction
code = " void dostuff(const char *x) { \n "
" f(x); \n "
" } \n "
" \n "
" void test() { dostuff( \" abc \" ); } " ;
2019-08-05 16:26:32 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 2 , " \" abc \" " , ValueFlow : : Value : : TOK ) ) ;
2014-08-03 20:11:22 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowPointerAlias ( ) {
2014-08-03 20:11:22 +02:00
const char * code ;
2019-02-22 06:38:56 +01:00
std : : list < ValueFlow : : Value > values ;
2014-08-03 20:11:22 +02:00
code = " const char * f() { \n "
" static const char *x; \n "
" static char ret[10]; \n "
" if (a) x = &ret[0]; \n "
" return x; \n "
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5 , " & ret [ 0 ] " , ValueFlow : : Value : : TOK ) ) ;
2014-08-05 06:24:23 +02:00
// dead pointer
code = " void f() { \n "
" int *x; \n "
" if (cond) { int i; x = &i; } \n "
" *x = 0; \n " // <- x can point at i
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " & i " , ValueFlow : : Value : : TOK ) ) ;
2015-11-15 23:38:23 +01:00
code = " void f() { \n "
" struct X *x; \n "
" x = &x[1]; \n "
" } " ;
2019-02-22 06:38:56 +01:00
values = tokenValues ( code , " & " ) ;
values . remove_if ( & isNotTokValue ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
values = tokenValues ( code , " x [ " ) ;
values . remove_if ( & isNotTokValue ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2014-08-03 20:11:22 +02:00
}
2018-11-10 21:30:01 +01:00
2018-11-10 16:40:40 +01:00
void valueFlowLifetime ( ) {
const char * code ;
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
code = " void f() { \n "
" int a = 1; \n "
" auto x = [&]() { return a + 1; }; \n "
" auto b = x; \n "
" } \n " ;
2019-02-22 06:38:56 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " a + 1 " , ValueFlow : : Value : : LIFETIME ) ) ;
2018-11-10 16:40:40 +01:00
code = " void f() { \n "
" int a = 1; \n "
" auto x = [=]() { return a + 1; }; \n "
" auto b = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4 , " a ; " , ValueFlow : : Value : : LIFETIME ) ) ;
code = " void f(int v) { \n "
" int a = v; \n "
" int * p = &a; \n "
" auto x = [=]() { return p + 1; }; \n "
" auto b = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5 , " a ; " , ValueFlow : : Value : : LIFETIME ) ) ;
code = " void f() { \n "
" std::vector<int> v; \n "
" auto x = v.begin(); \n "
" auto it = x; \n "
" } \n " ;
2019-02-22 06:38:56 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " v . begin " , ValueFlow : : Value : : LIFETIME ) ) ;
2018-11-10 16:40:40 +01:00
}
2014-08-03 20:11:22 +02:00
2015-02-24 15:57:39 +01:00
void valueFlowArrayElement ( ) {
const char * code ;
code = " void f() { \n "
2015-07-27 16:25:14 +02:00
" const int x[] = {43,23,12}; \n "
2015-02-24 15:57:39 +01:00
" return x; \n "
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , " { 43 , 23 , 12 } " , ValueFlow : : Value : : TOK ) ) ;
2015-02-24 15:57:39 +01:00
code = " void f() { \n "
2015-07-27 16:25:14 +02:00
" const char x[] = \" abcd \" ; \n "
2015-02-24 15:57:39 +01:00
" return x; \n "
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , " \" abcd \" " , ValueFlow : : Value : : TOK ) ) ;
2015-07-27 16:25:14 +02:00
code = " void f() { \n "
" char x[32] = \" abcd \" ; \n "
" return x; \n "
" } " ;
2018-11-10 16:40:40 +01:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , " \" abcd \" " , ValueFlow : : Value : : TOK ) ) ;
2015-11-07 15:07:26 +01:00
code = " void f() { \n "
" int a[10]; \n "
" int *x = a; \n " // <- a value is a
" *x = 0; \n " // .. => x value is a
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " a " , ValueFlow : : Value : : TOK ) ) ;
2015-11-12 16:14:27 +01:00
code = " char f() { \n "
" const char *x = \" abcd \" ; \n "
" return x[0]; \n "
" } " ;
ASSERT_EQUALS ( ( int ) ( ' a ' ) , valueOfTok ( code , " [ " ) . intvalue ) ;
code = " char f() { \n "
" const char *x = \" \" ; \n "
" return x[0]; \n "
" } " ;
ASSERT_EQUALS ( 0 , valueOfTok ( code , " [ " ) . intvalue ) ;
2015-02-24 15:57:39 +01:00
}
2016-11-20 15:14:49 +01:00
void valueFlowMove ( ) {
const char * code ;
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f() { \n "
" X x; \n "
" g(std::forward<X>(x)); \n "
" y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : ForwardedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f() { \n "
" X x; \n "
" g(std::move(x).getA()); \n " // Only parts of x might be moved out
" y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f() { \n "
" X x; \n "
" g(std::forward<X>(x).getA()); \n " // Only parts of x might be moved out
" y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : ForwardedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" x.clear(); \n "
" y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" y=x->y; \n "
" z=x->z; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f(int i) { \n "
" X x; \n "
" z = g(std::move(x)); \n "
" y = x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
2016-12-12 21:46:05 +01:00
code = " void f(int i) { \n "
" X x; \n "
" y = g(std::move(x), \n "
" x.size()); \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-12-12 21:46:05 +01:00
2016-11-20 15:14:49 +01:00
code = " void f(int i) { \n "
" X x; \n "
" x = g(std::move(x)); \n "
" y = x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " A f(int i) { \n "
" X x; \n "
" if (i) "
" return g(std::move(x)); \n "
" return h(std::move(x)); \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2018-12-02 14:36:01 +01:00
code = " struct X { \n "
" }; \n "
" struct Data { \n "
" template<typename Fun> \n "
" void foo(Fun f) {} \n "
" }; \n "
" Data g(X value) { return Data(); } \n "
" void f() { \n "
" X x; \n "
" g(std::move(x)).foo([=](int value) mutable {;}); \n "
" X y=x; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 11U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2019-12-21 07:39:14 +01:00
code = " void f(int x) { \n "
" g(std::move(x)); \n "
" y=x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowCalculations ( ) {
2014-01-18 19:30:44 +01:00
const char * code ;
2015-07-18 15:03:57 +02:00
2015-07-26 12:00:42 +02:00
// Different operators
ASSERT_EQUALS ( 5 , valueOfTok ( " 3 + (a ? b : 2); " , " + " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 - (a ? b : 2); " , " - " ) . intvalue ) ;
ASSERT_EQUALS ( 6 , valueOfTok ( " 3 * (a ? b : 2); " , " * " ) . intvalue ) ;
ASSERT_EQUALS ( 6 , valueOfTok ( " 13 / (a ? b : 2); " , " / " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 13 % (a ? b : 2); " , " % " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 == (a ? b : 2); " , " == " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 != (a ? b : 2); " , " != " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 > (a ? b : 2); " , " > " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 >= (a ? b : 2); " , " >= " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 < (a ? b : 2); " , " < " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 <= (a ? b : 2); " , " <= " ) . intvalue ) ;
2016-12-20 21:37:25 +01:00
ASSERT_EQUALS ( 1 , valueOfTok ( " (UNKNOWN_TYPE)1; " , " ( " ) . intvalue ) ;
ASSERT ( tokenValues ( " (UNKNOWN_TYPE)1000; " , " ( " ) . empty ( ) ) ; // don't know if there is truncation, sign extension
2016-12-20 19:32:21 +01:00
ASSERT_EQUALS ( 255 , valueOfTok ( " (unsigned char)~0; " , " ( " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " (int)0; " , " ( " ) . intvalue ) ;
2016-12-20 23:09:50 +01:00
ASSERT_EQUALS ( 3 , valueOfTok ( " (int)(1+2); " , " ( " ) . intvalue ) ;
2016-12-20 19:32:21 +01:00
ASSERT_EQUALS ( 0 , valueOfTok ( " (UNKNOWN_TYPE*)0; " , " ( " ) . intvalue ) ;
ASSERT_EQUALS ( 100 , valueOfTok ( " (int)100.0; " , " ( " ) . intvalue ) ;
2018-12-27 21:33:01 +01:00
ASSERT_EQUALS ( 10 , valueOfTok ( " x = static_cast<int>(10); " , " ( 10 ) " ) . intvalue ) ;
2016-12-10 22:09:01 +01:00
2016-11-06 17:42:01 +01:00
// Don't calculate if there is UB
2016-11-20 17:59:50 +01:00
ASSERT ( tokenValues ( " ;-1<<10; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10<<-1; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10<<64; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;-1>>10; " , " >> " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10>>-1; " , " >> " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10>>64; " , " >> " ) . empty ( ) ) ;
2016-11-06 17:42:01 +01:00
2015-07-26 12:00:42 +02:00
// calculation using 1,2 variables/values
2014-01-18 19:30:44 +01:00
code = " void f(int x) { \n "
" a = x+456; \n "
" if (x==123) {} "
" } " ;
ASSERT_EQUALS ( 579 , valueOfTok ( code , " + " ) . intvalue ) ;
2014-01-20 21:45:30 +01:00
code = " void f(int x, int y) { \n "
" a = x+y; \n "
" if (x==123 || y==456) {} "
" } " ;
ASSERT_EQUALS ( 0 , valueOfTok ( code , " + " ) . intvalue ) ;
2014-01-18 19:30:44 +01:00
code = " void f(int x) { \n "
" a = x+x; \n "
" if (x==123) {} "
" } " ;
ASSERT_EQUALS ( 246 , valueOfTok ( code , " + " ) . intvalue ) ;
code = " void f(int x, int y) { \n "
2014-01-20 21:45:30 +01:00
" a = x*x; \n "
" if (x==2) {} \n "
" if (x==4) {} \n "
2014-01-18 19:30:44 +01:00
" } " ;
2014-01-20 21:45:30 +01:00
std : : list < ValueFlow : : Value > values = tokenValues ( code , " * " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 4 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 16 , values . back ( ) . intvalue ) ;
2014-06-13 16:34:57 +02:00
2016-12-04 22:39:59 +01:00
code = " void f(int x) { \n "
" if (x == 3) {} \n "
" a = x * (1 - x - 1); \n "
" } " ;
ASSERT_EQUALS ( - 9 , valueOfTok ( code , " * " ) . intvalue ) ;
2015-07-18 15:03:57 +02:00
// addition of different variables with known values
code = " int f(int x) { \n "
" int a = 1; \n "
" while (x!=3) { x+=a; } \n "
" return x/a; \n "
" } \n " ;
ASSERT_EQUALS ( 3 , valueOfTok ( code , " / " ) . intvalue ) ;
2015-07-02 20:11:27 +02:00
// ? :
code = " x = y ? 2 : 3; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 3 , values . back ( ) . intvalue ) ;
2015-07-02 20:52:04 +02:00
code = " void f(int a) { x = a ? 2 : 3; } \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 3 , values . back ( ) . intvalue ) ;
2016-08-15 14:19:35 +02:00
code = " x = (2<5) ? 2 : 3; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
2016-08-17 18:44:41 +02:00
code = " x = 123 ? : 456; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 123 , values . empty ( ) ? 0 : values . front ( ) . intvalue ) ;
2016-11-05 09:29:22 +01:00
// ~
code = " x = ~0U; " ;
settings . platform ( cppcheck : : Platform : : Native ) ; // ensure platform is native
values = tokenValues ( code , " ~ " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( ~ 0U , values . back ( ) . intvalue ) ;
2015-07-16 21:17:44 +02:00
// !
code = " void f(int x) { \n "
" a = !x; \n "
" if (x==0) {} \n "
" } " ;
values = tokenValues ( code , " ! " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . back ( ) . intvalue ) ;
2016-08-14 22:19:06 +02:00
// unary minus
code = " void f(int x) { \n "
" a = -x; \n "
" if (x==10) {} \n "
" } " ;
values = tokenValues ( code , " - " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( - 10 , values . back ( ) . intvalue ) ;
2018-07-23 08:51:59 +02:00
// Logical and
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = false && b; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = b && false; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = true && b; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = b && true; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
// Logical or
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = true || b; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = b || true; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = false || b; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2018-07-25 07:44:06 +02:00
code = " void f(bool b) { \n "
" bool x = b || false; \n "
" bool a = x; \n "
" } " ;
2018-07-23 08:51:59 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2019-01-03 07:05:31 +01:00
code = " bool f() { \n "
" bool a = (4 == 3); \n "
" bool b = (3 == 3); \n "
" return a || b; \n "
" } \n " ;
values = tokenValues ( code , " %oror% " ) ;
ASSERT_EQUALS ( 1 , values . size ( ) ) ;
if ( ! values . empty ( ) ) {
ASSERT_EQUALS ( true , values . front ( ) . isIntValue ( ) ) ;
ASSERT_EQUALS ( true , values . front ( ) . isKnown ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
}
2014-06-13 16:34:57 +02:00
// function call => calculation
2014-06-29 10:57:39 +02:00
code = " void f(int x, int y) { \n "
" a = x + y; \n "
" } \n "
" void callf() { \n "
" f(1,1); \n "
" f(10,10); \n "
" } " ;
values = tokenValues ( code , " + " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
if ( ! values . empty ( ) ) {
/* todo.. */
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 22 , values . back ( ) . intvalue ) ;
}
2015-08-02 18:12:03 +02:00
// Comparison of string
values = tokenValues ( " f( \" xyz \" == \" xyz \" ); " , " == " ) ; // implementation defined
ASSERT_EQUALS ( 0U , values . size ( ) ) ; // <- no value
values = tokenValues ( " f( \" xyz \" == 0); " , " == " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f(0 == \" xyz \" ); " , " == " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f( \" xyz \" != 0); " , " != " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f(0 != \" xyz \" ); " , " != " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
2014-01-18 19:30:44 +01:00
}
2014-01-06 07:44:58 +01:00
2018-03-23 08:28:12 +01:00
void valueFlowSizeof ( ) {
const char * code ;
std : : list < ValueFlow : : Value > values ;
2019-03-11 20:32:24 +01:00
// array size
code = " void f() { \n "
" char a[10]; "
" x = sizeof(*a); \n "
" } " ;
values = tokenValues ( code , " ( * " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . back ( ) . intvalue ) ;
2018-03-23 08:28:12 +01:00
# define CHECK(A, B) \
code = " void f() { \n " \
" x = sizeof( " A " ); \n " \
" } " ; \
values = tokenValues ( code , " ( " A " ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B , values . back ( ) . intvalue ) ;
// standard types
CHECK ( " void * " , settings . sizeof_pointer ) ;
CHECK ( " char " , 1U ) ;
CHECK ( " short " , settings . sizeof_short ) ;
CHECK ( " int " , settings . sizeof_int ) ;
CHECK ( " long " , settings . sizeof_long ) ;
2019-05-01 16:34:28 +02:00
CHECK ( " wchar_t " , settings . sizeof_wchar_t ) ;
2019-10-20 21:02:28 +02:00
// string/char literals
CHECK ( " \" asdf \" " , 5 ) ;
CHECK ( " L \" asdf \" " , 5 * settings . sizeof_wchar_t ) ;
CHECK ( " u8 \" asdf \" " , 5 ) ; // char8_t
CHECK ( " u \" asdf \" " , 5 * 2 ) ; // char16_t
CHECK ( " U \" asdf \" " , 5 * 4 ) ; // char32_t
CHECK ( " 'a' " , 1U ) ;
CHECK ( " 'ab' " , settings . sizeof_int ) ;
CHECK ( " L'a' " , settings . sizeof_wchar_t ) ;
CHECK ( " u8'a' " , 1U ) ; // char8_t
CHECK ( " u'a' " , 2U ) ; // char16_t
CHECK ( " U'a' " , 4U ) ; // char32_t
2018-03-23 08:28:12 +01:00
# undef CHECK
// array size
code = " void f() { \n "
" struct S *a[10]; "
" x = sizeof(a) / sizeof(a[0]); \n "
" } " ;
values = tokenValues ( code , " / " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 10 , values . back ( ) . intvalue ) ;
# define CHECK(A, B, C, D) \
code = " enum " A " E " B " { E0, E1 }; \n " \
" void f() { \n " \
" x = sizeof( " C " ); \n " \
" } " ; \
values = tokenValues ( code , " ( " C " ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( D , values . back ( ) . intvalue ) ;
// enums
CHECK ( " " , " " , " E " , settings . sizeof_int ) ;
// typed enums
CHECK ( " " , " : char " , " E " , 1U ) ;
CHECK ( " " , " : signed char " , " E " , 1U ) ;
CHECK ( " " , " : unsigned char " , " E " , 1U ) ;
CHECK ( " " , " : short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : signed short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : unsigned short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : signed int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : unsigned int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : signed long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : unsigned long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : signed long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : unsigned long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : wchar_t " , " E " , settings . sizeof_wchar_t ) ;
CHECK ( " " , " : size_t " , " E " , settings . sizeof_size_t ) ;
// enumerators
CHECK ( " " , " " , " E0 " , settings . sizeof_int ) ;
// typed enumerators
CHECK ( " " , " : char " , " E0 " , 1U ) ;
CHECK ( " " , " : signed char " , " E0 " , 1U ) ;
CHECK ( " " , " : unsigned char " , " E0 " , 1U ) ;
CHECK ( " " , " : short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : signed short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : unsigned short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : signed int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : unsigned int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : signed long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : unsigned long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : signed long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : unsigned long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : wchar_t " , " E0 " , settings . sizeof_wchar_t ) ;
CHECK ( " " , " : size_t " , " E0 " , settings . sizeof_size_t ) ;
// class typed enumerators
CHECK ( " class " , " : char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : signed char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : unsigned char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : signed short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : unsigned short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : signed int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : unsigned int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : signed long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : unsigned long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : signed long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : unsigned long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : wchar_t " , " E :: E0 " , settings . sizeof_wchar_t ) ;
CHECK ( " class " , " : size_t " , " E :: E0 " , settings . sizeof_size_t ) ;
# undef CHECK
# define CHECK(A, B) \
code = " enum E " A " { E0, E1 }; \n " \
" void f() { \n " \
" E arrE[] = { E0, E1 }; \n " \
" x = sizeof(arrE); \n " \
" } " ; \
values = tokenValues ( code , " ( arrE ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B * 2U , values . back ( ) . intvalue ) ;
// enum array
CHECK ( " " , settings . sizeof_int ) ;
// typed enum array
CHECK ( " : char " , 1U ) ;
CHECK ( " : signed char " , 1U ) ;
CHECK ( " : unsigned char " , 1U ) ;
CHECK ( " : short " , settings . sizeof_short ) ;
CHECK ( " : signed short " , settings . sizeof_short ) ;
CHECK ( " : unsigned short " , settings . sizeof_short ) ;
CHECK ( " : int " , settings . sizeof_int ) ;
CHECK ( " : signed int " , settings . sizeof_int ) ;
CHECK ( " : unsigned int " , settings . sizeof_int ) ;
CHECK ( " : long " , settings . sizeof_long ) ;
CHECK ( " : signed long " , settings . sizeof_long ) ;
CHECK ( " : unsigned long " , settings . sizeof_long ) ;
CHECK ( " : long long " , settings . sizeof_long_long ) ;
CHECK ( " : signed long long " , settings . sizeof_long_long ) ;
CHECK ( " : unsigned long long " , settings . sizeof_long_long ) ;
CHECK ( " : wchar_t " , settings . sizeof_wchar_t ) ;
CHECK ( " : size_t " , settings . sizeof_size_t ) ;
# undef CHECK
# define CHECK(A, B) \
code = " enum class E " A " { E0, E1 }; \n " \
" void f() { \n " \
" E arrE[] = { E::E0, E::E1 }; \n " \
" x = sizeof(arrE); \n " \
" } " ; \
values = tokenValues ( code , " ( arrE ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B * 2U , values . back ( ) . intvalue ) ;
// enum array
CHECK ( " " , settings . sizeof_int ) ;
// typed enum array
CHECK ( " : char " , 1U ) ;
CHECK ( " : signed char " , 1U ) ;
CHECK ( " : unsigned char " , 1U ) ;
CHECK ( " : short " , settings . sizeof_short ) ;
CHECK ( " : signed short " , settings . sizeof_short ) ;
CHECK ( " : unsigned short " , settings . sizeof_short ) ;
CHECK ( " : int " , settings . sizeof_int ) ;
CHECK ( " : signed int " , settings . sizeof_int ) ;
CHECK ( " : unsigned int " , settings . sizeof_int ) ;
CHECK ( " : long " , settings . sizeof_long ) ;
CHECK ( " : signed long " , settings . sizeof_long ) ;
CHECK ( " : unsigned long " , settings . sizeof_long ) ;
CHECK ( " : long long " , settings . sizeof_long_long ) ;
CHECK ( " : signed long long " , settings . sizeof_long_long ) ;
CHECK ( " : unsigned long long " , settings . sizeof_long_long ) ;
CHECK ( " : wchar_t " , settings . sizeof_wchar_t ) ;
CHECK ( " : size_t " , settings . sizeof_size_t ) ;
# undef CHECK
2019-03-13 18:31:41 +01:00
code = " uint16_t arr[10]; \n "
" x = sizeof(arr); " ;
values = tokenValues ( code , " ( arr ) " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
2019-03-13 19:01:54 +01:00
ASSERT_EQUALS ( 10 * sizeof ( std : : uint16_t ) , values . back ( ) . intvalue ) ;
2018-03-23 08:28:12 +01:00
}
2017-05-19 14:34:59 +02:00
void valueFlowErrorPath ( ) {
const char * code ;
code = " void f() { \n "
" int x = 53; \n "
" a = x; \n "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=53', assigned value is 53 \n " ,
2017-05-19 14:34:59 +02:00
getErrorPathForX ( code , 3U ) ) ;
code = " void f(int y) { \n "
" int x = y; \n "
" a = x; \n "
" y += 12; \n "
" if (y == 32) {} "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 5,Assuming that condition 'y==32' is not redundant \n "
2017-08-24 22:02:49 +02:00
" 4,Compound assignment '+=', before assignment value is 20 \n "
2017-05-20 08:47:35 +02:00
" 2,Assignment 'x=y', assigned value is 20 \n " ,
2017-05-19 14:34:59 +02:00
getErrorPathForX ( code , 3U ) ) ;
code = " void f1(int x) { \n "
" a = x; \n "
" } \n "
" void f2() { \n "
" int x = 3; \n "
" f1(x+1); \n "
" } \n " ;
2019-08-05 16:26:32 +02:00
ASSERT_EQUALS ( " 5,Assignment 'x=3', assigned value is 3 \n "
" 6,Calling function 'f1', 1st argument 'x+1' value is 4 \n " ,
getErrorPathForX ( code , 2U ) ) ;
2017-05-19 16:32:58 +02:00
code = " void f(int a) { \n "
" int x; \n "
" for (x = a; x < 50; x++) {} \n "
" b = x; \n "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 3,After for loop, x has value 50 \n " ,
2017-05-19 16:32:58 +02:00
getErrorPathForX ( code , 4U ) ) ;
2017-05-19 14:34:59 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeCondition ( ) {
2014-01-08 06:39:15 +01:00
const char * code ;
code = " void f(int x) { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
2014-01-04 20:57:02 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-06 07:44:58 +01:00
2014-01-08 06:53:17 +01:00
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x >= 1) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 1 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 17:37:39 +01:00
2014-01-19 20:16:55 +01:00
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x > 0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x > 1) {} \n " // not zero => don't consider > condition
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 1 ) ) ;
code = " void f(int x) { \n " // not unsigned => don't consider > condition
" int a = x; \n "
2014-01-20 06:31:28 +01:00
" if (x > 0) {} \n "
2014-01-19 20:16:55 +01:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 17:37:39 +01:00
code = " void f(int *x) { \n "
" *x = 100; \n "
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 06:53:17 +01:00
2014-01-10 05:47:56 +01:00
code = " extern const int x; \n "
" void f() { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2018-02-24 22:07:34 +01:00
// after loop
code = " void f(struct X *x) { \n "
" do { \n "
" if (!x) \n "
" break; \n "
" } while (x->a); \n "
" if (x) {} \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionAssignIncDec ( ) { // assignment / increment
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-10 05:47:56 +01:00
2014-01-11 15:36:09 +01:00
code = " void f(int x) { \n "
" x = 2 + x; \n "
" if (x == 65); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 65 ) ) ;
2014-01-11 20:53:23 +01:00
code = " void f(int x) { \n "
" x = y = 2 + x; \n "
" if (x == 65); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 65 ) ) ;
2014-01-11 15:36:09 +01:00
2014-01-17 19:28:28 +01:00
code = " void f(int x) { \n "
" a[x++] = 0; \n "
" if (x == 5); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 5 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x++; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 3 ) ) ;
2017-08-25 23:07:26 +02:00
ASSERT_EQUALS ( " 4,Assuming that condition 'x==4' is not redundant \n "
" 3,x is incremented, before this increment the value is 3 \n " ,
getErrorPathForX ( code , 2U ) ) ;
2014-01-17 19:28:28 +01:00
2017-04-25 20:45:02 +02:00
// compound assignment += , -= , ...
code = " void f(int x) { \n "
" a = x; \n "
" x += 2; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 2 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x -= 2; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 6 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x *= 2; \n "
" if (x == 42); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 21 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x /= 5; \n "
" if (x == 42); \n "
" } " ;
ASSERT ( tokenValues ( code , " x ; " ) . empty ( ) ) ;
2014-01-18 08:45:24 +01:00
// bailout: assignment
bailout ( " void f(int x) { \n "
" x = y; \n "
" if (x == 123) {} \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable y \n "
" [test.cpp:2]: (debug) valueflow.cpp::valueFlowReverse bailout: assignment of x \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionAndAndOrOrGuard ( ) { // guarding by &&
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-11 12:44:55 +01:00
code = " void f(int x) { \n "
" if (!x || \n " // <- x can be 0
" a/x) {} \n " // <- x can't be 0
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-11 11:30:34 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-11 14:54:10 +01:00
code = " void f(int *x) { \n "
2014-01-11 15:18:39 +01:00
" ((x=ret())&& \n "
" (*x==0)); \n " // <- x is not 0
2014-01-11 14:54:10 +01:00
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2015-09-27 13:29:28 +02:00
code = " void f(int *x) { \n "
" int a = (x && *x == '1'); \n "
" int b = a ? atoi(x) : 0; \n " // <- x is not 0
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionFunctionCall ( ) { // function calls
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-11 14:54:10 +01:00
2014-01-11 14:31:51 +01:00
code = " void f(int x) { \n "
" a = x; \n "
" setx(x); \n "
" if (x == 1) {} \n "
" } " ;
2014-04-02 17:33:04 +02:00
ASSERT_EQUALS ( true , testValueOfX ( ( std : : string ( " void setx(int x); " ) + code ) . c_str ( ) , 2U , 1 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( ( std : : string ( " void setx(int &x); " ) + code ) . c_str ( ) , 2U , 1 ) ) ;
2014-03-18 17:04:33 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 1 ) ) ;
2014-01-11 14:31:51 +01:00
2014-01-12 18:19:00 +01:00
code = " void f(char* x) { \n "
" strcpy(x, \" abc \" ); \n "
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-13 05:52:28 +01:00
code = " void addNewFunction(Scope**scope, const Token**tok); \n "
" void f(Scope *x) { \n "
" x->functionList.back(); \n "
" addNewFunction(&x,&tok); \n " // address-of, x can be changed by subfunction
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionLoop ( ) { // while, for, do-while
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-13 05:52:28 +01:00
2014-01-12 11:58:10 +01:00
code = " void f(int x) { \n " // loop condition, x is not assigned inside loop => use condition
2014-01-11 20:25:49 +01:00
" a = x; \n " // x can be 37
" while (x == 37) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 37 ) ) ;
2016-11-27 11:40:42 +01:00
code = " void f(int x) { \n " // loop condition, x is assigned inside loop => don't use condition
2014-01-11 20:25:49 +01:00
" a = x; \n " // don't assume that x can be 37
" while (x != 37) { x++; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 37 ) ) ;
2014-12-14 14:10:42 +01:00
code = " void f(int x) { \n "
" a = x; \n "
" for (; x!=1; x++) { } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 1 ) ) ;
2014-01-14 17:57:50 +01:00
code = " void f(menu *x) { \n "
" a = x->parent; \n "
" for (i=0;(i<10) && (x!=0); i++) { x = x->next; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-12 11:58:10 +01:00
code = " void f(int x) { \n " // condition inside loop, x is NOT assigned inside loop => use condition
" a = x; \n "
" do { \n "
" if (x==76) {} \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 76 ) ) ;
2016-11-27 11:40:42 +01:00
code = " void f(int x) { \n " // conditions inside loop, x is assigned inside do-while => don't use condition
2014-01-12 11:58:10 +01:00
" a = x; \n "
" do { \n "
" if (x!=76) { x=do_something(); } \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 76 ) ) ;
2014-01-18 11:54:00 +01:00
2016-11-27 11:40:42 +01:00
code = " void f(X x) { \n " // conditions inside loop, x is assigned inside do-while => don't use condition
2014-01-18 11:54:00 +01:00
" a = x; \n "
" for (i=1;i<=count;i++) { \n "
" BUGON(x==0) \n "
" x = x.next; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionTernaryOp ( ) { // bailout: ?:
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-12 11:58:10 +01:00
2014-01-07 19:46:13 +01:00
bailout ( " void f(int x) { \n "
" y = ((x<0) ? x : ((x==2)?3:4)); \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable y \n "
" [test.cpp:2]: (debug) valueflow.cpp:1113:valueFlowReverse bailout: no simplification of x within ?: expression \n " , errout . str ( ) ) ;
2014-01-08 06:39:15 +01:00
bailout ( " int f(int x) { \n "
" int r = x ? 1 / x : 0; \n "
" if (x == 0) {} \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1113:valueFlowReverse bailout: no simplification of x within ?: expression \n " , errout . str ( ) ) ;
2014-01-08 06:39:15 +01:00
code = " void f(int x) { \n "
2014-01-10 16:13:39 +01:00
" int a =v x; \n "
2014-01-08 06:39:15 +01:00
" a = b ? x/2 : 20/x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-07 19:46:13 +01:00
2016-10-16 07:15:28 +02:00
code = " void f(const s *x) { \n "
" x->a = 0; \n "
" if (x ? x->a : 0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-10 16:13:39 +01:00
code = " void f(int x, int y) { \n "
" a = x; \n "
" if (y){} \n "
" if (x==123){} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionSizeof ( ) { // skip sizeof
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-10 16:13:39 +01:00
2014-01-11 21:10:01 +01:00
code = " void f(int *x) { \n "
" sizeof(x[0]); \n "
" if (x==63){} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 63 ) ) ;
2014-04-29 20:09:11 +02:00
code = " void f(int *x) { \n "
" char a[sizeof x.y]; \n "
" if (x==0){} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-11 21:10:01 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionIfElse ( ) { // bailout: if/else/etc
2014-01-19 09:05:48 +01:00
const char * code ;
code = " void f(X * x) { \n "
" a = x; \n "
" if ((x != NULL) && \n "
" (a(x->name, html)) && \n "
" (a(x->name, body))) {} \n "
" if (x != NULL) { } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-19 09:31:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-19 09:05:48 +01:00
2014-01-06 11:27:56 +01:00
bailout ( " void f(int x) { \n "
" if (x != 123) { b = x; } \n "
" if (x == 123) {} \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable b \n "
" [test.cpp:2]: (debug) valueflow.cpp:1144:valueFlowReverse bailout: variable x stopping on } \n " , errout . str ( ) ) ;
2014-06-30 00:02:49 +02:00
code = " void f(int x) { \n "
" a = x; \n "
" if (abc) { x = 1; } \n " // <- condition must be false if x is 7 in next line
" if (x == 7) { } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 7 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-06 11:27:56 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionGlobalVariables ( ) {
2014-01-19 11:55:02 +01:00
const char * code ;
2017-10-17 16:55:37 +02:00
// handle global variables
code = " int x; \n "
" void f() { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3 , 123 ) ) ;
// bailout when there is function call
2014-01-19 11:55:02 +01:00
code = " class Fred { int x; void clear(); void f(); }; \n "
" void Fred::f() { \n "
" int a = x; \n "
" clear(); \n " // <- x might be assigned
" if (x == 234) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3 , 234 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-11 21:21:00 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionSwitch ( ) {
2014-01-11 21:21:00 +01:00
// bailout: switch
2014-01-12 15:07:58 +01:00
// TODO : handle switch/goto more intelligently
2014-01-11 21:21:00 +01:00
bailout ( " void f(int x, int y) { \n "
" switch (y) { \n "
" case 1: a=x; break; \n "
" case 2: if (x==5) {} break; \n "
" }; \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a \n "
" [test.cpp:3]: (debug) valueflow.cpp:1180:valueFlowReverse bailout: variable x stopping on break \n " , errout . str ( ) ) ;
2014-01-12 15:07:58 +01:00
bailout ( " void f(int x, int y) { \n "
" switch (y) { \n "
" case 1: a=x; return 1; \n "
" case 2: if (x==5) {} break; \n "
" }; \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a \n "
" [test.cpp:3]: (debug) valueflow.cpp:1180:valueFlowReverse bailout: variable x stopping on return \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-12 17:16:51 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionMacro ( ) {
2014-01-12 17:16:51 +01:00
// bailout: condition is a expanded macro
2017-05-18 21:52:31 +02:00
bailout ( " #define M if (x==123) {} \n "
" void f(int x) { \n "
2014-01-12 17:16:51 +01:00
" a = x; \n "
2017-05-18 21:52:31 +02:00
" M; \n "
2014-01-12 17:16:51 +01:00
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a \n "
" [test.cpp:4]: (debug) valueflow.cpp:1260:valueFlowBeforeCondition bailout: variable x, condition is defined in macro \n " , errout . str ( ) ) ;
2019-07-27 20:02:49 +02:00
bailout ( " #define FREE(obj) ((obj) ? (free((char *) (obj)), (obj) = 0) : 0) \n " // #8349
" void f(int *x) { \n "
" a = x; \n "
" FREE(x); \n "
" } " ) ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a \n "
" [test.cpp:4]: (debug) valueflow.cpp:1260:valueFlowBeforeCondition bailout: variable x, condition is defined in macro \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-13 16:07:25 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionGoto ( ) {
2014-01-13 16:07:25 +01:00
// bailout: goto label (TODO: handle gotos more intelligently)
bailout ( " void f(int x) { \n "
" if (x == 123) { goto out; } \n "
" a=x; \n " // <- x is not 123
" out: "
" if (x==123){} \n "
" } " ) ;
2019-09-26 10:32:25 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS (
" [test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a \n "
2020-02-13 16:27:06 +01:00
" [test.cpp:4]: (debug) valueflow.cpp:1131:valueFlowReverse bailout: variable x stopping on goto label \n " ,
2019-09-26 10:32:25 +02:00
errout . str ( ) ) ;
2014-04-28 06:21:48 +02:00
// #5721 - FP
bailout ( " static void f(int rc) { \n "
" ABC* abc = getabc(); \n "
" if (!abc) { goto out }; \n "
" \n "
" abc->majortype = 0; \n "
" if (FAILED(rc)) {} \n "
" \n "
" out: \n "
" if (abc) {} \n "
" } \n " ) ;
2019-09-26 10:32:25 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS (
" [test.cpp:2]: (debug) valueflow.cpp:1035:valueFlowReverse bailout: assignment of abc \n "
2020-02-13 16:27:06 +01:00
" [test.cpp:8]: (debug) valueflow.cpp:1131:valueFlowReverse bailout: variable abc stopping on goto label \n " ,
2019-09-26 10:32:25 +02:00
errout . str ( ) ) ;
2014-01-04 20:57:02 +01:00
}
2014-01-06 16:37:52 +01:00
2019-10-05 15:42:47 +02:00
void valueFlowBeforeConditionForward ( ) {
2019-10-03 09:58:57 +02:00
const char * code ;
code = " void f(int a) { \n "
" int x = a; \n "
" if (a == 123) {} \n "
" int b = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int a) { \n "
" int x = a; \n "
" if (a != 123) {} \n "
" int b = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
}
2014-11-20 14:20:09 +01:00
void valueFlowAfterAssign ( ) {
2014-01-21 21:13:49 +01:00
const char * code ;
code = " void f() { \n "
" int x = 123; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2016-12-19 21:21:18 +01:00
code = " void f() { \n "
" bool x = 32; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
2014-01-21 21:13:49 +01:00
code = " void f() { \n "
" int x = 123; \n "
" a = sizeof(x); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
2014-01-22 06:10:17 +01:00
code = " void f() { \n "
" int x = 123; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2014-01-22 20:16:31 +01:00
2014-01-24 18:22:38 +01:00
code = " void f() { \n "
" int x = 9; \n "
" --x; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2015-05-02 17:30:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 8 ) ) ;
2017-08-25 22:15:52 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=9', assigned value is 9 \n "
" 3,x is decremented', new value is 8 \n " ,
getErrorPathForX ( code , 4U ) ) ;
2014-01-24 18:22:38 +01:00
2016-10-15 19:09:50 +02:00
code = " void x() { \n "
" int x = value ? 6 : 0; \n "
" x = \n "
" 1 + x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 7 ) ) ;
2014-05-03 12:49:07 +02:00
code = " void f() { \n "
" int x = 0; \n "
" y = x += z; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-01-25 18:31:02 +01:00
code = " void f() { \n "
" static int x = 2; \n "
" x++; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
2014-02-22 12:09:54 +01:00
code = " void f() { \n "
" static int x = 2; \n "
" a >> x; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
2014-03-23 17:57:27 +01:00
code = " void f() { \n "
" static int x = 0; \n "
" if (x==0) x = getX(); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2019-05-01 17:05:16 +02:00
// truncation
code = " int f() { \n "
" int x = 1.5; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
code = " int f() { \n "
" unsigned char x = 0x123; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0x23 ) ) ;
code = " int f() { \n "
" signed char x = 0xfe; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , - 2 ) ) ;
2014-01-24 17:47:49 +01:00
// function
code = " void f() { \n "
" char *x = 0; \n "
" int success = getx((char**)&x); \n "
" if (success) x[0] = 0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-04-01 07:06:20 +02:00
code = " void f() { \n "
" char *x = 0; \n "
" getx(reinterpret_cast<void **>(&x)); \n "
" *x = 0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2015-07-26 19:28:42 +02:00
// lambda
code = " void f() { \n "
" int x = 0; \n "
" Q q = [&]() { \n "
" if (x > 0) {} \n "
" x++; \n "
" }; \n "
" dosomething(q); \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2018-12-04 18:46:00 +01:00
code = " void f() { \n "
" int x = 0; \n "
" dostuff([&]() { \n "
" if (x > 0) {} \n "
" x++; \n "
" }); \n "
" dosomething(q); \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2018-12-04 18:54:26 +01:00
code = " int f() { \n "
" int x = 1; \n "
" dostuff([&]() { \n "
" x = y; \n "
" }); \n "
" return x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 1 ) ) ;
2015-11-30 16:15:58 +01:00
// ?:
code = " void f() { \n "
" int x = 8; \n "
" a = ((x > 10) ? \n "
" x : 0); \n " // <- x is not 8
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 8 ) ) ;
code = " void f() { \n " // #6973
" char *x = \" \" ; \n "
" a = ((x[0] == 'U') ? \n "
" x[1] : 0); \n " // <- x is not ""
" } " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , " \" \" " , ValueFlow : : Value : : TOK ) ) ;
2015-11-30 16:15:58 +01:00
2015-12-01 07:49:19 +01:00
code = " void f() { \n " // #6973
" char *x = getenv ( \" LC_ALL \" ); \n "
" if (x == NULL) \n "
" x = \" \" ; \n "
" \n "
" if ( (x[0] == 'U') && \n " // x can be ""
" (x[1] ? \n " // x can't be ""
" x[3] : \n " // x can't be ""
" x[2] )) \n " // x can't be ""
" {} \n "
" } \n " ;
2018-11-10 16:40:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 6U , " \" \" " , ValueFlow : : Value : : TOK ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , " \" \" " , ValueFlow : : Value : : TOK ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , " \" \" " , ValueFlow : : Value : : TOK ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , " \" \" " , ValueFlow : : Value : : TOK ) ) ;
2015-12-01 07:49:19 +01:00
2016-07-17 21:51:20 +02:00
code = " void f() { \n " // #7599
" t *x = 0; \n "
" y = (a ? 1 : x \n " // <- x is 0
" && x->y ? 1 : 2); " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f() { \n " // #7599
" t *x = 0; \n "
" y = (a ? 1 : !x \n " // <- x is 0
" || x->y ? 1 : 2); " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-01-22 20:16:31 +01:00
// if/else
code = " void f() { \n "
" int x = 123; \n "
" if (condition) return; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f() { \n "
" int x = 1; \n "
" if (condition) x = 2; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 1 ) ) ;
2014-08-03 20:11:22 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 2 ) ) ;
2014-01-22 20:16:31 +01:00
code = " void f() { \n "
" int x = 123; \n "
" if (condition1) x = 456; \n "
" if (condition2) x = 789; \n "
2014-08-05 08:28:46 +02:00
" a = 2 + x; \n " // <- either assignment "x=123" is redundant or x can be 123 here.
2014-01-22 20:16:31 +01:00
" } " ;
2020-02-16 16:02:22 +01:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 5U , 123 ) ) ;
2014-01-22 20:16:31 +01:00
2014-01-24 18:22:38 +01:00
code = " void f(int a) { \n "
" int x = 123; \n "
" if (a > 1) \n "
" ++x; \n "
" else \n "
" ++x; \n "
" return 2 + x; \n "
" } " ;
2020-01-05 16:25:33 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
2014-01-24 18:22:38 +01:00
2014-01-22 20:16:31 +01:00
code = " void f() { \n "
" int x = 1; \n "
" if (condition1) x = 2; \n "
" else return; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 1 ) ) ;
2014-01-25 19:13:33 +01:00
2014-01-26 15:50:25 +01:00
code = " void f(){ \n "
" int x = 0; \n "
" if (a>=0) { x = getx(); } \n "
" if (x==0) { return; } \n "
" return 123 / x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-31 15:43:34 +01:00
code = " void f() { \n "
" X *x = getx(); \n "
2015-10-27 12:33:46 +01:00
" if(0) { x = 0; } \n "
2014-01-31 15:43:34 +01:00
" else { x->y = 1; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2015-10-27 12:33:46 +01:00
code = " void f() { \n " // #6239
" int x = 4; \n "
" if(1) { x = 0; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 4 ) ) ;
2014-03-18 17:04:33 +01:00
code = " void f() { \n "
" int x = 32; \n "
" if (x>=32) return; \n "
" a[x]=0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 32 ) ) ;
code = " void f() { \n "
" int x = 32; \n "
" if (x>=32) { \n "
" a[x] = 0; \n " // <- should have possible value 32
" return; \n "
" } \n "
" } " ;
2014-06-15 17:15:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 32 ) ) ;
2014-03-18 17:04:33 +01:00
2015-01-01 14:29:49 +01:00
code = " void f() { \n "
" int x = 33; \n "
" if (x==33) goto fail; \n "
" a[x]=0; \n "
" fail: \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 33 ) ) ;
2014-04-22 16:10:20 +02:00
code = " void f() { \n "
" int x = 32; \n "
" if (a==1) { z=x+12; } \n "
" if (a==2) { z=x+32; } \n "
" z = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 32 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 32 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 32 ) ) ;
2014-04-18 16:10:18 +02:00
code = " void f() { \n " // #5656 - FP
" int x = 0; \n "
" if (!x) { \n "
" x = getx(); \n "
" } \n "
" y = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ;
2015-02-08 19:20:05 +01:00
code = " void f(int y) { \n " // alias
" int x = y; \n "
" if (y == 54) {} \n "
" else { a = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 54 ) ) ;
2014-04-26 11:27:58 +02:00
code = " void f () { \n "
" ST * x = g_pST; \n "
" if (x->y == 0) { \n "
" x = NULL; \n "
" return 1; \n "
" } \n "
" a = x->y; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-04-26 14:41:28 +02:00
code = " void f () { \n "
" ST * x = g_pST; \n "
" if (x->y == 0) { \n "
" x = NULL; \n "
" goto label; \n "
" } \n "
" a = x->y; \n "
" label: \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-05-01 15:15:26 +02:00
code = " void f() { \n " // #5752 - FP
" int *x = 0; \n "
" if (x && *x == 123) { \n "
" getx(*x); \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-30 18:12:33 +02:00
code = " void f() { \n "
" int x = 0; \n "
" if (!x) {} \n "
" else { y = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-09-04 17:52:14 +02:00
code = " void f() { \n " // #6118 - FP
" int x = 0; \n "
" x = x & 0x1; \n "
" if (x == 0) { x = 2; } \n "
2015-10-14 10:44:04 +02:00
" y = 42 / x; \n " // <- x is 2
2014-09-04 17:52:14 +02:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2015-10-14 10:44:04 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
2014-09-04 17:52:14 +02:00
code = " void f() { \n " // #6118 - FN
" int x = 0; \n "
" x = x & 0x1; \n "
" if (x == 0) { x += 2; } \n "
2015-10-14 10:44:04 +02:00
" y = 42 / x; \n " // <- x is 2
2014-09-04 17:52:14 +02:00
" } " ;
2015-10-14 10:44:04 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2020-02-13 16:27:06 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
2014-09-04 17:52:14 +02:00
2015-01-06 14:12:35 +01:00
code = " void f(int mode) { \n "
" struct ABC *x; \n "
" \n "
" if (mode) { x = &y; } \n "
" else { x = NULL; } \n "
" \n "
" if (!x) exit(1); \n "
" \n "
" a = x->a; \n " // <- x can't be 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 0 ) ) ;
2018-07-25 22:59:54 +02:00
code = " void f(int i) { \n "
2018-07-25 23:02:16 +02:00
" bool x = false; \n "
" if (i == 0) { x = true; } \n "
" else if (x && i == 1) {} \n "
" } \n " ;
2018-07-25 22:59:54 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f(int i) { \n "
2018-07-25 23:02:16 +02:00
" bool x = false; \n "
" while(i > 0) { \n "
" i++; \n "
" if (i == 0) { x = true; } \n "
" else if (x && i == 1) {} \n "
" } \n "
" } \n " ;
2020-01-05 16:25:33 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 6U , 0 ) ) ;
2018-07-25 22:59:54 +02:00
2014-01-25 19:13:33 +01:00
// multivariables
code = " void f(int a) { \n "
" int x = a; \n "
" if (a!=132) { b = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 132 ) ) ;
code = " void f(int a) { \n "
" int x = a; \n "
2014-02-17 20:07:38 +01:00
" b = x; \n " // <- line 3
2014-01-25 19:13:33 +01:00
" if (a!=132) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 132 ) ) ;
2014-01-25 20:14:49 +01:00
code = " void f() { \n "
" int a; \n "
" if (n) { a = n; } \n "
" else { a = 0; } \n "
" int x = a; \n "
2014-02-17 20:07:38 +01:00
" if (a > 0) { a = b / x; } \n " // <- line 6
2014-01-25 20:14:49 +01:00
" } " ;
2014-02-17 20:07:38 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ; // x is not 0 at line 6
2014-08-27 17:11:38 +02:00
code = " void f(int x1) { \n " // #6086
" int x = x1; \n "
" if (x1 >= 3) { \n "
" return; \n "
" } \n "
" a = x; \n " // <- x is not 3
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 3 ) ) ;
2015-02-07 10:45:30 +01:00
code = " int f(int *x) { \n " // #5980
" if (!x) { \n "
" switch (i) { \n "
" default: \n "
" throw std::runtime_error(msg); \n "
" }; \n "
" } \n "
" return *x; \n " // <- x is not 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 0 ) ) ;
2015-07-12 19:35:47 +02:00
code = " void f(int a) { \n " // #6826
" int x = a ? a : 87; \n "
" if (a && x) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 87 ) ) ;
2016-01-24 08:57:57 +01:00
code = " void f() { \n "
" int first=-1, x=0; \n "
" do { \n "
" if (first >= 0) { a = x; } \n " // <- x is not 0
" first++; x=3; \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-10-20 15:54:02 +02:00
// pointer/reference to x
code = " int f(void) { \n "
" int x = 2; \n "
" int *px = &x; \n "
" for (int i = 0; i < 1; i++) { \n "
" *px = 1; \n "
" } \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 2 ) ) ;
code = " int f(void) { \n "
" int x = 5; \n "
" int &rx = x; \n "
" for (int i = 0; i < 1; i++) { \n "
" rx = 1; \n "
" } \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 5 ) ) ;
2014-02-17 20:07:38 +01:00
// break
code = " void f() { \n "
" for (;;) { \n "
" int x = 1; \n "
" if (!abc()) { \n "
" x = 2; \n "
" break; \n "
" } \n "
" a = x; \n " // <- line 8
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 2 ) ) ; // x is not 2 at line 8
2014-06-30 17:56:42 +02:00
code = " void f() { \n "
" int x; \n "
" switch (ab) { \n "
" case A: x = 12; break; \n "
" case B: x = 34; break; \n "
" } \n "
" v = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 12 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 34 ) ) ;
2014-07-16 09:12:56 +02:00
code = " void f() { \n " // #5981
" int x; \n "
" switch (ab) { \n "
" case A: x = 12; break; \n "
" case B: x = 34; break; \n "
" } \n "
" switch (ab) { \n "
" case A: v = x; break; \n " // <- x is not 34
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 34 ) ) ;
2014-09-23 16:06:02 +02:00
// while/for
2014-10-11 17:48:51 +02:00
code = " void f() { \n " // #6138
" ENTRY *x = 0; \n "
" while (x = get()) { \n "
" set(x->value); \n " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-09-23 16:06:02 +02:00
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" break; \n "
" } \n "
" } \n "
" a = x; \n " // <- x can be 0
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 9U , 0 ) ) ; // x can be 0 at line 9
2019-08-03 21:12:14 +02:00
code = " void f(const int *buf) { \n "
" int x = 111; \n "
" bool found = false; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" found = true; \n "
" break; \n "
" } \n "
" } \n "
" if (found) \n "
" a = x; \n " // <- x can't be 111
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 12U , 111 ) ) ; // x can not be 111 at line 9
2014-09-23 16:06:02 +02:00
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" ; \n " // <- no break
" } \n "
" } \n "
2016-11-27 11:40:42 +01:00
" a = x; \n " // <- x can't be 0
2014-09-23 16:06:02 +02:00
" } \n " ;
2016-11-27 11:40:42 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 0 ) ) ; // x can't be 0 at line 9
2014-09-23 16:06:02 +02:00
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" while (++i < 10) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" break; \n "
" } \n "
" } \n "
" a = x; \n " // <- x can be 0
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 9U , 0 ) ) ; // x can be 0 at line 9
2016-02-08 10:43:41 +01:00
code = " void f(const int a[]) { \n " // #6616
" const int *x = 0; \n "
" for (int i = 0; i < 10; i = *x) { \n " // <- x is not 0
" x = a[i]; \n "
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2016-11-21 17:26:36 +01:00
// alias
code = " void f() { \n " // #7778
" int x = 0; \n "
" int *p = &x; \n "
" x = 3; \n "
" *p = 2; \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 3 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 6U , 2 ) ) ;
2014-01-21 21:13:49 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowAfterCondition ( ) {
2014-06-15 16:47:01 +02:00
const char * code ;
2015-07-28 08:58:05 +02:00
// in if
2014-06-15 16:47:01 +02:00
code = " void f(int x) { \n "
" if (x == 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x != 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
2018-04-05 06:51:31 +02:00
code = " void f(int x) { \n "
" if (x > 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 124 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x < 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 122 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
// ----
code = " void f(int x) { \n "
" if (123 < x) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 124 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (123 > x) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 122 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
2015-07-28 08:58:05 +02:00
// in else
2014-06-15 16:47:01 +02:00
code = " void f(int x) { \n "
" if (x == 123) {} \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x != 123) {} \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2014-06-16 16:39:41 +02:00
2015-07-28 08:58:05 +02:00
// after if
code = " void f(int x) { \n "
" if (x == 10) { \n "
" x++; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 10 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 5U , 11 ) ) ;
2014-06-16 16:39:41 +02:00
// !
code = " void f(int x) { \n "
" if (!x) { a = x; } \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-07-07 17:48:58 +02:00
code = " void f(int x, int y) { \n "
" if (!(x&&y)) { return; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2016-01-18 15:39:20 +01:00
code = " void f(int x) { \n "
" if (!x) { { throw new string(); }; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2018-04-08 09:24:01 +02:00
code = " void f(int x) { \n "
" if (x != 123) { throw " " ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2018-04-09 16:13:17 +02:00
code = " void f(int x) { \n "
" if (x != 123) { } \n "
" else { throw " " ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x == 123) { } \n "
" else { throw " " ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
2018-04-08 09:24:01 +02:00
code = " void f(int x) { \n "
" if (x < 123) { } \n "
" else { a = x; } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x < 123) { throw \" \" ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2018-04-09 16:13:17 +02:00
code = " void f(int x) { \n "
" if (x < 123) { } \n "
" else { throw \" \" ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 122 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x > 123) { } \n "
" else { a = x; } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x > 123) { throw \" \" ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x > 123) { } \n "
" else { throw \" \" ; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 124 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x < 123) { return; } \n "
" else { return; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 124 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
2014-06-18 06:57:48 +02:00
// if (var)
code = " void f(int x) { \n "
" if (x) { a = x; } \n " // <- x is not 0
" else { b = x; } \n " // <- x is 0
" c = x; \n " // <- x might be 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
2014-06-18 05:51:23 +02:00
// After while
code = " void f(int x) { \n "
" while (x != 3) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 3 ) ) ;
2014-06-19 17:29:41 +02:00
2014-08-16 18:32:25 +02:00
code = " void f(int x) { \n "
" while (11 != (x = dostuff())) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 11 ) ) ;
code = " void f(int x) { \n "
" while (11 != (x = dostuff()) && y) {} \n "
" a = x; \n "
" } " ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 11 ) ) ;
code = " void f(int x) { \n "
" while (x = dostuff()) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(const Token *x) { \n " // #5866
" x = x->next(); \n "
" while (x) { x = x->next(); } \n "
" if (x->str()) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f(const Token *x) { \n "
" while (0 != (x = x->next)) {} \n "
" x->ab = 0; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(const Token* x) { \n "
" while (0 != (x = x->next)) {} \n "
" if (x->str) { \n " // <- possible value 0
" x = y; \n " // <- this caused some problem
" } \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2014-06-25 16:00:56 +02:00
// conditional code after if/else/while
code = " void f(int x) { \n "
" if (x == 2) {} \n "
" if (x > 0) \n "
2014-10-17 06:50:33 +02:00
" a = x; \n " // <- TODO, x can be 2
2014-06-25 16:00:56 +02:00
" else \n "
" b = x; \n "
" } " ;
2019-08-11 15:39:37 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 2 ) ) ;
2014-06-25 16:00:56 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 2 ) ) ;
2014-08-01 07:35:15 +02:00
// condition with 2nd variable
code = " void f(int x) { \n "
" int y = 0; \n "
" if (x == 7) { y = 1; } \n "
" if (!y) \n "
" a = x; \n " // <- x can not be 7 here
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 7 ) ) ;
2014-10-17 06:50:33 +02:00
code = " void f(struct X *x) { \n "
" bool b = TRUE; \n "
" if(x) { } \n "
" else \n "
" b = FALSE; \n "
" if (b) \n "
" abc(x->value); \n " // <- x is not 0
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-06-19 17:29:41 +02:00
// In condition, after && and ||
code = " void f(int x) { \n "
" a = (x != 3 || \n "
" x); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 3 ) ) ;
code = " void f(int x) { \n "
" a = (x == 4 && \n "
" x); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 4 ) ) ;
2014-06-25 06:17:44 +02:00
2014-08-11 16:21:20 +02:00
// protected usage with &&
code = " void f(const Token* x) { \n "
" if (x) {} \n "
" for (; x && \n "
" x->str() != y; x = x->next()) {} \n "
" } " ;
2020-02-13 16:27:06 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-11 16:21:20 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f(const Token* x) { \n "
" if (x) {} \n "
" if (x && \n "
" x->str() != y) {} \n "
" } " ;
2015-02-01 15:05:00 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-11 16:21:20 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-08-27 16:59:18 +02:00
// return
code = " void f(int x) { \n " // #6024
2014-08-26 18:48:11 +02:00
" if (x == 5) { \n "
" if (z) return; else return; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 5 ) ) ;
2015-08-11 11:21:03 +02:00
code = " void f(int x) { \n " // #6730
" if (x == 5) { \n "
" if (z) continue; else throw e; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 5 ) ) ;
2014-06-25 06:17:44 +02:00
// TODO: float
code = " void f(float x) { \n "
" if (x == 0.5) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2017-09-03 23:24:55 +02:00
// aliased variable
code = " void f() { \n "
" int x = 1; \n "
" int *data = &x; \n "
" if (!x) { \n "
" calc(data); \n "
" a = x; \n " // <- x might be changed by calc
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ;
2019-08-08 07:46:47 +02:00
code = " int* g(); \n "
" int f() { \n "
" int * x; \n "
" x = g(); \n "
" if (x) { printf( \" \" ); } \n "
" return *x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 6U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 6U , 0 ) ) ;
2014-06-15 16:47:01 +02:00
}
2019-09-26 10:32:49 +02:00
void valueFlowAfterConditionExpr ( ) {
2019-09-26 10:32:25 +02:00
const char * code ;
code = " void f(int* p) { \n "
" if (p[0] == 123) { \n "
" int x = p[0]; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int y) { \n "
" if (y+1 == 123) { \n "
" int x = y+1; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int y) { \n "
" if (y+1 == 123) { \n "
" int x = y+2; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 124 ) ) ;
code = " void f(int y, int z) { \n "
" if (y+z == 123) { \n "
" int x = y+z; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f(int y, int z) { \n "
" if (y+z == 123) { \n "
" y++; \n "
" int x = y+z; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 123 ) ) ;
code = " void f(int y) { \n "
" if (y++ == 123) { \n "
" int x = y++; \n "
" int a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 124 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 125 ) ) ;
}
2019-05-29 09:45:15 +02:00
void valueFlowAfterConditionSeveralNot ( ) {
const char * code ;
code = " int f(int x, int y) { \n "
" if (x!=0) {} \n "
" return y/x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2019-05-30 14:41:14 +02:00
code = " int f(int x, int y) { \n "
2019-05-29 09:45:15 +02:00
" if (!!(x != 0)) { \n "
" return y/x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
code = " int f(int x, int y) { \n "
" if (!!!(x != 0)) { \n "
" return y/x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " int f(int x, int y) { \n "
" if (!!!!(x != 0)) { \n "
" return y/x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
}
2017-08-23 11:13:47 +02:00
void valueFlowForwardCompoundAssign ( ) {
const char * code ;
code = " void f() { \n "
" int x = 123; \n "
" x += 43; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 166 ) ) ;
2017-08-24 22:02:49 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=123', assigned value is 123 \n "
" 3,Compound assignment '+=', assigned value is 166 \n " ,
getErrorPathForX ( code , 4U ) ) ;
2017-08-23 11:13:47 +02:00
2017-08-23 17:52:28 +02:00
code = " void f() { \n "
" int x = 123; \n "
" x /= 0; \n " // don't crash when evaluating x/=0
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
2017-08-23 11:13:47 +02:00
code = " void f() { \n "
" float x = 123.45; \n "
" x += 67; \n "
" return x; \n "
" } " ;
2017-10-11 22:36:51 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123.45F + 67 , 0.01F ) ) ;
2017-08-23 11:13:47 +02:00
}
2017-08-27 19:50:44 +02:00
void valueFlowForwardCorrelatedVariables ( ) {
const char * code ;
code = " void f(int x = 0) { \n "
" bool zero(x==0); \n "
" if (zero) a = x; \n " // <- x is 0
" else b = x; \n " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
}
2018-08-10 18:05:23 +02:00
void valueFlowForwardModifiedVariables ( ) {
const char * code ;
code = " void f(bool b) { \n "
" int x = 0; \n "
" if (b) x = 1; \n "
" else b = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfXKnown ( code , 4U , 0 ) ) ;
code = " void f(int i) { \n "
" int x = 0; \n "
" if (i == 0) \n "
" x = 1; \n "
" else if (!x && i == 1) \n "
" int b = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfXKnown ( code , 5U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfXKnown ( code , 6U , 0 ) ) ;
}
2017-09-20 12:53:25 +02:00
void valueFlowForwardFunction ( ) {
const char * code ;
code = " class C { \n "
" public: \n "
2017-09-20 14:03:56 +02:00
" C(int &i); \n " // non-const argument => might be changed
2017-09-20 12:53:25 +02:00
" }; \n "
" int f() { \n "
" int x=1; \n "
" C c(x); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 1 ) ) ;
2017-09-20 14:03:56 +02:00
code = " class C { \n "
" public: \n "
" C(const int &i); \n " // const argument => is not changed
" }; \n "
" int f() { \n "
" int x=1; \n "
" C c(x); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 8U , 1 ) ) ;
2018-11-26 13:59:28 +01:00
code = " int f(int *); \n "
" int g() { \n "
" const int a = 1; \n "
" int x = 11; \n "
" c = (a && f(&x)); \n "
" if (x == 42) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 11 ) ) ;
2017-09-20 12:53:25 +02:00
}
2018-03-16 19:13:48 +01:00
void valueFlowForwardTernary ( ) {
const char * code ;
code = " int f() { \n "
" int x=5; \n "
" a = b ? init1(&x) : init2(&x); \n "
" return 1 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 5 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 5 ) ) ;
2019-02-28 20:34:07 +01:00
code = " int f(int *p) { \n " // #9008 - gcc ternary ?:
" if (p) return; \n "
" x = *p ? : 1; \n " // <- no explicit expr0
" } " ;
testValueOfX ( code , 1U , 0 ) ; // do not crash
2019-10-20 15:20:05 +02:00
code = " void f(int a) { \n " // #8784
" int x = 13; \n "
" if (a == 1) x = 26; \n "
" return a == 1 ? x : 0; \n " // <- x is 26
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 13 ) ) ;
2020-02-13 16:27:06 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 26 ) ) ;
2018-03-16 19:13:48 +01:00
}
2017-08-28 22:39:12 +02:00
void valueFlowForwardLambda ( ) {
const char * code ;
code = " void f() { \n "
" int x=1; \n "
" auto f = [&](){ a=x; } \n " // x is not 1
" x = 2; \n "
" f(); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 2 ) ) ;
code = " void f() { \n "
" int x=3; \n "
" auto f = [&](){ a=x; } \n " // todo: x is 3
" f(); \n "
" } " ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 3 ) ) ;
}
2014-11-20 14:20:09 +01:00
void valueFlowBitAnd ( ) {
2014-04-14 06:45:39 +02:00
const char * code ;
code = " int f(int a) { \n "
" int x = a & 0x80; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0x80 ) ) ;
2015-07-04 11:17:38 +02:00
code = " int f(int a) { \n "
" int x = a & 0x80 ? 1 : 2; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0x80 ) ) ;
2015-10-14 10:44:04 +02:00
code = " int f() { \n "
" int x = (19 - 3) & 15; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 16 ) ) ;
2014-04-14 06:45:39 +02:00
}
2018-11-03 23:25:46 +01:00
void valueFlowRightShift ( ) {
const char * code ;
2019-01-01 14:15:50 +01:00
/* Set some temporary fixed values to simplify testing */
const Settings settingsTmp = settings ;
settings . int_bit = 32 ;
settings . long_bit = 64 ;
settings . long_long_bit = MathLib : : bigint_bits * 2 ;
2018-11-03 23:25:46 +01:00
code = " int f(int a) { \n "
" int x = (a & 0xff) >> 16; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " int f(unsigned int a) { \n "
" int x = (a % 123) >> 16; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2019-01-01 14:15:50 +01:00
code = " int f(int y) { \n "
" int x = (y & 0xFFFFFFF) >> 31; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(int y) { \n "
" int x = (y & 0xFFFFFFF) >> 32; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(short y) { \n "
" int x = (y & 0xFFFFFF) >> 31; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(short y) { \n "
" int x = (y & 0xFFFFFF) >> 32; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long y) { \n "
" int x = (y & 0xFFFFFF) >> 63; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long y) { \n "
" int x = (y & 0xFFFFFF) >> 64; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long long y) { \n "
" int x = (y & 0xFFFFFF) >> 63; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long long y) { \n "
" int x = (y & 0xFFFFFF) >> 64; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long long y) { \n "
" int x = (y & 0xFFFFFF) >> 121; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
code = " int f(long long y) { \n "
" int x = (y & 0xFFFFFF) >> 128; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3u , 0 ) ) ;
settings = settingsTmp ;
2018-11-03 23:25:46 +01:00
}
2018-12-31 17:05:46 +01:00
void valueFlowFwdAnalysis ( ) {
const char * code ;
std : : list < ValueFlow : : Value > values ;
code = " void f() { \n "
" struct Foo foo; \n "
" foo.x = 1; \n "
" x = 0 + foo.x; \n " // <- foo.x is 1
" } " ;
values = tokenValues ( code , " + " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( true , values . front ( ) . isKnown ( ) ) ;
ASSERT_EQUALS ( true , values . front ( ) . isIntValue ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
2019-01-01 18:23:47 +01:00
2019-01-02 18:05:55 +01:00
code = " void f() { \n "
" S s; \n "
" s.x = 1; \n "
" int y = 10; \n "
" while (s.x < y) \n " // s.x does not have known value
" s.x++; \n "
" } " ;
values = tokenValues ( code , " < " ) ;
2020-02-16 16:02:22 +01:00
ASSERT_EQUALS ( 1 , values . size ( ) ) ;
ASSERT ( values . front ( ) . isPossible ( ) ) ;
ASSERT_EQUALS ( true , values . front ( ) . intvalue ) ;
2019-01-02 18:05:55 +01:00
2019-07-29 15:51:48 +02:00
code = " void f() { \n "
" S s; \n "
" s.x = 37; \n "
" int y = 10; \n "
" while (s.x < y) \n " // s.x has a known value
" y--; \n "
" } " ;
values = tokenValues ( code , " . x < " ) ;
ASSERT ( values . size ( ) = = 1 & &
values . front ( ) . isKnown ( ) & &
values . front ( ) . isIntValue ( ) & &
values . front ( ) . intvalue = = 37 ) ;
2019-01-01 18:23:47 +01:00
code = " void f() { \n "
" Hints hints; \n "
" hints.x = 1; \n "
" if (foo) \n "
" hints.x = 2; \n "
" x = 0 + foo.x; \n " // <- foo.x is possible 1, possible 2
" } " ;
values = tokenValues ( code , " + " ) ;
TODO_ASSERT_EQUALS ( 2U , 0U , values . size ( ) ) ; // should be 2
2019-06-17 21:25:15 +02:00
// FP: Condition '*b>0' is always true
code = " bool dostuff(const char *x, const char *y); \n "
" void fun(char *s, int *b) { \n "
" for (int i = 0; i < 42; ++i) { \n "
" if (dostuff(s, \" 1 \" )) { \n "
" *b = 1; \n "
" break; \n "
" } \n "
" } \n "
" if (*b > 0) { \n " // *b does not have known value
" } \n "
" } " ;
values = tokenValues ( code , " > " ) ;
2020-02-16 16:02:22 +01:00
ASSERT_EQUALS ( 1 , values . size ( ) ) ;
ASSERT ( values . front ( ) . isPossible ( ) ) ;
ASSERT_EQUALS ( true , values . front ( ) . intvalue ) ;
2019-06-17 21:25:15 +02:00
2019-07-24 19:16:35 +02:00
code = " void foo() { \n "
" struct ISO_PVD_s pvd; \n "
" pvd.descr_type = 0xff; \n "
" do { \n "
" if (pvd.descr_type == 0xff) {} \n "
" dostuff(&pvd); \n "
" } while (condition) \n "
" } " ;
values = tokenValues ( code , " == " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2019-12-20 19:06:35 +01:00
// for loops
code = " struct S { int x; }; \n " // #9036
" void foo(struct S s) { \n "
" for (s.x = 0; s.x < 127; s.x++) {} \n "
" } " ;
values = tokenValues ( code , " < " ) ; // TODO: comparison can be true or false
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2018-12-31 17:05:46 +01:00
}
2015-07-20 19:45:38 +02:00
void valueFlowSwitchVariable ( ) {
const char * code ;
code = " void f(int x) { \n "
2017-10-20 17:31:58 +02:00
" a = x - 1; \n " // <- x can be 14
2015-07-20 19:45:38 +02:00
" switch (x) { \n "
2017-10-16 21:51:30 +02:00
" case 14: a=x+2; break; \n " // <- x is 14
2015-07-20 19:45:38 +02:00
" }; \n "
" a = x; \n " // <- x can be 14
" } " ;
2015-07-29 19:54:57 +02:00
ASSERT_EQUALS ( true , testConditionalValueOfX ( code , 2U , 14 ) ) ;
2019-10-18 16:16:56 +02:00
TODO_ASSERT_EQUALS ( true , false , testConditionalValueOfX ( code , 4U , 14 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testConditionalValueOfX ( code , 6U , 14 ) ) ;
2017-10-16 21:51:30 +02:00
2017-10-20 17:31:58 +02:00
ValueFlow : : Value value1 = valueOfTok ( code , " - " ) ;
ASSERT_EQUALS ( 13 , value1 . intvalue ) ;
ASSERT ( ! value1 . isKnown ( ) ) ;
2017-10-16 21:51:30 +02:00
2017-10-20 17:31:58 +02:00
ValueFlow : : Value value2 = valueOfTok ( code , " + " ) ;
2019-10-18 16:16:56 +02:00
TODO_ASSERT_EQUALS ( 16 , 0 , value2 . intvalue ) ;
TODO_ASSERT_EQUALS ( true , false , value2 . isKnown ( ) ) ;
2015-07-20 19:45:38 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowForLoop ( ) {
2014-01-10 16:51:58 +01:00
const char * code ;
2020-02-15 07:57:43 +01:00
ValueFlow : : Value value ;
2014-01-10 16:51:58 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 10 ) ) ;
2014-08-18 16:45:22 +02:00
code = " void f() { \n "
2014-12-30 18:50:22 +01:00
" int x; \n "
" for (x = 2; x < 1; x++) \n "
2014-08-18 16:45:22 +02:00
" a[x] = 0; \n " // <- not 2
2014-12-30 18:50:22 +01:00
" b = x; \n " // 2
2014-08-18 16:45:22 +02:00
" } " ;
2014-12-30 18:50:22 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
code = " void f() { \n "
" int x; \n "
" for (x = 2; x < 1; ++x) \n "
" a[x] = 0; \n " // <- not 2
" b = x; \n " // 2
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
2014-08-18 16:45:22 +02:00
2016-12-20 07:54:38 +01:00
code = " enum AB {A,B}; \n " // enum => handled by valueForLoop2
" void f() { \n "
" int x; \n "
" for (x = 1; x < B; ++x) \n "
" a[x] = 0; \n " // <- not 1
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 1 ) ) ;
2014-03-29 20:20:22 +01:00
code = " void f(int a) { \n "
" for (int x = a; x < 10; x++) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
2019-03-12 18:53:58 +01:00
code = " void f() { \n "
" for (int x = 0; x < 5; x += 2) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 4 ) ) ;
2014-03-22 19:02:33 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x = x + 2) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 8 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 10 ) ) ;
2014-03-23 20:37:56 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x = x / 0) \n "
" a[x] = 0; \n "
" } " ;
2014-03-24 00:16:02 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ; // don't crash
2014-03-23 20:37:56 +01:00
2014-02-22 17:58:48 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" x<4 ? \n "
" a[x] : 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2014-03-25 18:22:22 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" x==0 ? \n "
" 0 : a[x]; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-04-28 15:54:54 +02:00
2014-12-30 19:56:47 +01:00
code = " void f() { \n " // #5223
" for (int x = 0; x < 300 && x < 18; x++) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 17 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 299 ) ) ;
2014-04-28 15:54:54 +02:00
code = " void f() { \n "
" int x; \n "
" for (int i = 0; x = bar[i]; i++) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-06-30 07:26:48 +02:00
2015-02-07 18:14:22 +01:00
code = " void f() { \n "
" const char abc[] = \" abc \" ; \n "
" int x; \n "
" for (x = 0; abc[x] != ' \\ 0'; x++) {} \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 3 ) ) ;
2014-06-30 07:26:48 +02:00
code = " void f() { \n " // #5939
" int x; \n "
" for (int x = 0; (x = do_something()) != 0;) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f() { \n "
" int x; \n "
" for (int x = 0; x < 10 && y = do_something();) \n "
" x; \n "
" } " ;
2016-12-20 07:54:38 +01:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-17 08:44:55 +02:00
2014-08-17 06:42:16 +02:00
code = " void f() { \n "
" int x,y; \n "
" for (x = 0, y = 0; x < 10, y < 10; x++, y++) \n " // usage of ,
" x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-17 08:44:55 +02:00
code = " void foo(double recoveredX) { \n "
" for (double x = 1e-18; x < 1e40; x *= 1.9) { \n "
" double relativeError = (x - recoveredX) / x; \n "
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-01 16:12:57 +02:00
2018-01-11 14:27:41 +01:00
// Ticket #7139
// "<<" in third expression of for
code = " void f(void) { \n "
" int bit, x; \n "
" for (bit = 1, x = 0; bit < 128; bit = bit << 1, x++) { \n "
" z = x; \n " // <- known value [0..6]
" } \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 6 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 7 ) ) ;
2014-08-01 16:12:57 +02:00
// &&
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x > 1 \n "
" && x) {} " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 9 ) ) ;
2016-12-11 21:19:24 +01:00
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x < value \n "
" && x) {} " // <- maybe x is not 9
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2014-08-01 16:12:57 +02:00
// ||
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x == 0 \n "
" || x) {} " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 9 ) ) ;
2014-08-13 04:03:17 +02:00
2014-08-17 10:40:22 +02:00
// After loop
code = " void foo() { \n "
" int x; \n "
" for (x = 0; x < 10; x++) {} \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 10 ) ) ;
code = " void foo() { \n "
" int x; \n "
" for (x = 0; 2 * x < 20; x++) {} \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 10 ) ) ;
code = " void foo() { \n " // related with #887
" int x; \n "
" for (x = 0; x < 20; x++) {} \n "
" a = x++; \n "
" } \n " ;
2015-05-02 17:30:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 20 ) ) ;
2014-08-17 10:40:22 +02:00
2015-01-05 14:00:12 +01:00
code = " void f() { \n "
" int x; \n "
" for (x = 0; x < 5; x++) {} \n "
" if (x == 5) { \n "
2019-08-08 07:46:47 +02:00
" abort(); \n "
2015-01-05 14:00:12 +01:00
" } \n "
2015-01-05 16:39:47 +01:00
" a = x; \n " // <- x can't be 5
2015-01-05 14:00:12 +01:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 5 ) ) ;
2015-01-05 16:39:47 +01:00
code = " void f() { \n "
" int x; \n "
" for (x = 0; x < 5; x++) {} \n "
" if (x < 5) {} \n "
" else return; \n "
" a = x; \n " // <- x can't be 5
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 5 ) ) ;
2015-01-05 14:00:12 +01:00
2016-12-17 21:23:14 +01:00
// assert after for loop..
code = " static void f() { \n "
" int x; \n "
" int ctls[10]; \n "
" for (x = 0; x <= 10; x++) { \n "
" if (cond) \n "
" break; \n "
" } \n "
" assert(x <= 10); \n "
" ctls[x] = 123; \n " // <- x can't be 11
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 11 ) ) ;
2014-08-13 04:03:17 +02:00
// hang
code = " void f() { \n "
" for(int i = 0; i < 20; i++) \n "
" n = (int)(i < 10 || abs(negWander) < abs(negTravel)); \n "
" } " ;
2016-11-27 11:40:42 +01:00
testValueOfX ( code , 0 , 0 ) ; // <- don't hang
2016-01-24 13:11:51 +01:00
// conditional code in loop
code = " void f(int mask) { \n " // #6000
" for (int x = 10; x < 14; x++) { \n "
" int bit = mask & (1 << i); \n "
" if (bit) { \n "
" if (bit == (1 << 10)) {} \n "
" else { a = x; } \n " // <- x is not 10
" } \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 10 ) ) ;
2017-03-30 22:02:36 +02:00
// #7886 - valueFlowForLoop must be called after valueFlowAfterAssign
code = " void f() { \n "
" int sz = 4; \n "
" int x,y; \n "
" for(x=0,y=0; x < sz && y < 10; x++) \n "
" a = x; \n " // <- max value is 3
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 3 ) ) ;
2020-02-13 16:27:06 +01:00
code = " void f() { \n "
" int x; \n "
" for (x = 0; x < 10; x++) \n "
" x; \n "
" } " ;
std : : list < ValueFlow : : Value > values = tokenValues ( code , " x < " ) ;
ASSERT ( std : : none_of ( values . begin ( ) , values . end ( ) , std : : mem_fn ( & ValueFlow : : Value : : isUninitValue ) ) ) ;
2020-02-15 07:57:43 +01:00
// #9637
code = " void f() { \n "
" unsigned int x = 0; \n "
" for (x = 0; x < 2; x++) {} \n "
" } \n " ;
value = valueOfTok ( code , " x < " ) ;
ASSERT ( value . isPossible ( ) ) ;
ASSERT_EQUALS ( value . intvalue , 0 ) ;
code = " void f() { \n "
" unsigned int x = 0; \n "
" for (;x < 2; x++) {} \n "
" } \n " ;
value = valueOfTok ( code , " x < " ) ;
ASSERT ( value . isPossible ( ) ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
code = " void f() { \n "
" unsigned int x = 1; \n "
" for (x = 0; x < 2; x++) {} \n "
" } \n " ;
value = valueOfTok ( code , " x < " ) ;
ASSERT ( value . isPossible ( ) ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
2014-01-07 19:20:56 +01:00
}
2019-08-11 15:39:37 +02:00
void valueFlowSubFunction ( ) {
const char * code ;
code = " int f(int size) { \n "
" int x = 0; \n "
" if(size>16) { \n "
" x = size; \n "
" int a = x; \n "
" } \n "
" return x; \n "
" } \n "
" void g(){ \n "
" f(42); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 17 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 42 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 17 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 42 ) ) ;
2020-04-01 22:33:09 +02:00
code = " void g(int, int) {} \n "
" void f(int x, int y) { \n "
" g(x, y); \n "
" } \n "
" void h() { \n "
" f(0, 0); \n "
" f(1, 1); \n "
" f(2, 2); \n "
" f(3, 3); \n "
" f(4, 4); \n "
" f(5, 5); \n "
" f(6, 6); \n "
" f(7, 7); \n "
" f(8, 8); \n "
" f(9, 9); \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 2 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 3 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 4 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 5 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 6 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 7 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 8 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
2019-08-11 15:39:37 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowFunctionReturn ( ) {
2014-06-29 18:04:38 +02:00
const char * code ;
2016-10-20 16:10:55 +02:00
code = " int f1(int x) { \n "
2014-06-29 18:04:38 +02:00
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
2014-06-29 18:04:38 +02:00
2016-10-20 16:10:55 +02:00
code = " int add(int x, int y) { \n "
2014-06-29 18:04:38 +02:00
" return x+y; \n "
" } \n "
" void f2() { \n "
" x = 1 * add(10+1,4); \n "
" } " ;
ASSERT_EQUALS ( 15 , valueOfTok ( code , " * " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-10-20 16:10:55 +02:00
code = " int one() { return 1; } \n "
" void f() { x = 1 * one(); } " ;
ASSERT_EQUALS ( 1 , valueOfTok ( code , " * " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-10-22 17:22:57 +02:00
code = " int add(int x, int y) { \n "
" return x+y; \n "
" } \n "
" void f2() { \n "
" x = 1 * add(1,add(2,3)); \n "
" } " ;
ASSERT_EQUALS ( 6 , valueOfTok ( code , " * " ) . intvalue ) ;
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-11-20 15:14:49 +01:00
code = " int f(int i, X x) { \n "
" if (i) \n "
" return g(std::move(x)); \n "
" g(x); \n "
" return 0; \n "
" } " ;
2019-07-10 15:27:07 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MoveKind : : MovedVariable ) ) ;
2016-12-11 10:42:39 +01:00
code = " class A \n "
" { \n "
" int f1(int x) { \n "
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
ASSERT_EQUALS ( true , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
code = " class A \n "
" { \n "
" virtual int f1(int x) { \n "
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
ASSERT_EQUALS ( false , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
2014-06-29 18:04:38 +02:00
}
2015-02-03 22:12:05 +01:00
void valueFlowFunctionDefaultParameter ( ) {
const char * code ;
code = " class continuous_src_time { \n "
" continuous_src_time(std::complex<double> f, double st = 0.0, double et = infinity) {} \n "
" }; " ;
testValueOfX ( code , 2U , 2 ) ; // Don't crash (#6494)
}
2015-07-16 17:33:16 +02:00
2015-07-20 09:36:56 +02:00
bool isNotKnownValues ( const char code [ ] , const char str [ ] ) {
2019-06-17 13:17:45 +02:00
for ( const ValueFlow : : Value & v : tokenValues ( code , str ) ) {
if ( v . isKnown ( ) )
2015-07-20 09:36:56 +02:00
return false ;
}
2016-01-24 08:57:57 +01:00
return true ;
2015-07-20 09:36:56 +02:00
}
2015-07-16 17:33:16 +02:00
void knownValue ( ) {
const char * code ;
ValueFlow : : Value value ;
2015-07-25 19:36:29 +02:00
ASSERT ( valueOfTok ( " x = 1; " , " 1 " ) . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
// after assignment
code = " void f() { \n "
" int x = 1; \n "
" return x + 2; \n " // <- known value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 3 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
2016-01-27 19:20:00 +01:00
{
code = " void f() { \n "
" int x = 15; \n "
" if (x == 15) { x += 7; } \n " // <- condition is true
" } " ;
value = valueOfTok ( code , " == " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " int f() { \n "
" int a = 0, x = 0; \n "
" a = index(); \n "
" if (a != 0) \n "
" x = next(); \n "
" return x + 1; \n "
" } \n " ;
value = valueOfTok ( code , " + " ) ;
ASSERT ( value . isPossible ( ) ) ;
}
2016-01-26 16:10:15 +01:00
2015-07-16 17:33:16 +02:00
code = " void f() { \n "
" int x; \n "
" if (ab) { x = 7; } \n "
" return x + 2; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 9 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-16 17:33:16 +02:00
2017-06-01 15:16:07 +02:00
code = " void f(int c) { \n "
" int x = 0; \n "
" if (c) {} else { x++; } \n "
" return x + 2; \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " + " ) ) ;
2017-11-17 23:04:54 +01:00
code = " void f() { \n "
" int x = 0; \n "
" dostuff(&x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void f() { \n "
" int x = 0; \n "
" dostuff(0 ? ptr : &x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void f() { \n "
" int x = 0; \n "
" dostuff(unknown ? ptr : &x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2015-07-29 10:49:17 +02:00
code = " void f() { \n "
" int x = 0; \n "
" fred.dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2016-10-23 13:54:44 +02:00
code = " void dostuff(int x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
value = valueOfTok ( code , " < " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " void dostuff(int & x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void dostuff(const int & x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
value = valueOfTok ( code , " < " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2015-11-12 14:59:35 +01:00
code = " void f() { \n "
" int x = 0; \n "
" do { \n "
" if (x < 0) {} \n "
" fred.dostuff(x); \n "
" } while (abc); \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2017-07-09 12:50:17 +02:00
code = " int x; \n "
" void f() { \n "
" x = 4; \n "
" while (1) { \n "
" a = x+2; \n "
" dostuff(); \n "
" } \n "
" } " ;
ASSERT ( isNotKnownValues ( code , " + " ) ) ;
2015-07-21 17:56:40 +02:00
code = " void f() { \n "
" int x = 0; \n "
" if (y) { dostuff(x); } \n "
" if (!x) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-08-05 14:08:57 +02:00
code = " void f() { \n "
" int x = 0; \n "
" MACRO( v, { if (y) { x++; } } ); \n "
" if (!x) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-16 21:08:32 +02:00
code = " void f() { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (cond) { \n "
" x = 1; \n "
" break; \n "
" } \n "
" } \n "
" if (!x) {} \n " // <- possible value
" } " ;
2015-07-20 09:36:56 +02:00
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2019-06-30 17:49:44 +02:00
code = " void f() { \n " // #8356
" bool b = false; \n "
" for(int x = 3; !b && x < 10; x++) { \n " // <- b has known value
" for(int y = 4; !b && y < 20; y++) {} \n "
" } \n "
" } " ;
value = valueOfTok ( code , " ! " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2015-07-20 09:36:56 +02:00
code = " void f() { \n "
" int x = 0; \n "
" switch (state) { \n "
" case 1: \n "
" x = 1; \n "
" break; \n "
" } \n "
" if (!x) {} \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-16 21:08:32 +02:00
2015-11-08 14:08:47 +01:00
code = " void f() { \n " // #7049
" int x = 0; \n "
" switch (a) { \n "
" case 1: \n "
" x = 1; \n "
" case 2: \n "
" if (!x) {} \n " // <- possible value
" } \n "
" } " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-17 10:24:24 +02:00
code = " void f() { \n "
" int x = 0; \n "
" while (!x) { \n " // <- possible value
2015-07-18 15:35:39 +02:00
" scanf( \" %d \" , &x); \n "
2015-07-17 10:24:24 +02:00
" } \n "
" } " ;
value = valueOfTok ( code , " ! " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-17 10:24:24 +02:00
2015-07-29 11:55:07 +02:00
code = " void f() { \n "
" int x = 0; \n "
" do { } while (++x < 12); \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2015-07-17 20:30:34 +02:00
code = " void f() { \n "
2015-07-17 20:48:37 +02:00
" static int x = 0; \n "
2017-09-15 15:58:19 +02:00
" return x + 1; \n " // <- known value
2015-07-17 20:48:37 +02:00
" } \n " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
2017-09-15 15:58:19 +02:00
ASSERT ( value . isKnown ( ) ) ;
2015-07-17 20:48:37 +02:00
2015-07-26 17:05:21 +02:00
code = " void f() { \n "
" int x = 0; \n "
" a: \n "
" a = x + 1; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isPossible ( ) ) ;
2017-03-03 01:29:34 +01:00
// in conditional code
code = " void f(int x) { \n "
" if (!x) { \n "
" a = x+1; \n " // <- known value
" } \n "
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " void f(int x) { \n "
" if (a && 4==x && y) { \n "
" a = x+12; \n " // <- known value
" } \n "
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 16 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
// after condition
code = " int f(int x) { \n "
" if (x == 4) {} \n "
" return x + 1; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 5 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-16 20:49:14 +02:00
2016-01-30 20:03:55 +01:00
code = " int f(int x) { \n "
" if (x < 2) {} \n "
" else if (x >= 2) {} \n " // <- known value
" } " ;
value = valueOfTok ( code , " >= " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2016-01-30 22:13:03 +01:00
code = " int f(int x) { \n "
" if (x < 2) {} \n "
" else if (x > 2) {} \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " > " ) ) ;
2015-10-04 10:33:43 +02:00
// known and possible value
code = " void f() { \n "
" int x = 1; \n "
" int y = 2 + x; \n " // <- known value, don't care about condition
" if (x == 2) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ; // value of x can be 1
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 2 ) ) ; // value of x can't be 2
2016-01-26 10:07:42 +01:00
// calculation with known result
code = " int f(int x) { a = x & 0; } " ; // <- & is 0
value = valueOfTok ( code , " & " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2016-10-04 08:06:48 +02:00
2018-01-11 14:22:27 +01:00
// template parameters are not known
code = " template <int X> void f() { a = X; } \n "
" f<1>(); " ;
value = valueOfTok ( code , " 1 " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT_EQUALS ( false , value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
}
2016-10-26 10:36:02 +02:00
void valueFlowSizeofForwardDeclaredEnum ( ) {
const char * code = " enum E; sz=sizeof(E); " ;
valueOfTok ( code , " = " ) ; // Don't crash (#7775)
}
2017-01-09 15:53:08 +01:00
void valueFlowGlobalVar ( ) {
const char * code ;
code = " int x; \n "
" void f() { \n "
" x = 4; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 4 ) ) ;
code = " int x; \n "
" void f() { \n "
" if (x == 4) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 4 ) ) ;
code = " int x; \n "
" void f() { \n "
" x = 42; \n "
" unknownFunction(); \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 42 ) ) ;
}
2017-03-23 20:01:16 +01:00
2019-04-21 06:54:32 +02:00
void valueFlowGlobalConstVar ( ) {
const char * code ;
code = " const int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } " ;
2019-05-14 08:58:27 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 321 ) ) ;
code = " void f(const int x = 1) { \n "
" int a = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 2U , 1 ) ) ;
code = " volatile const int x = 42; \n "
" void f(){ int a = x; } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 2U , 42 ) ) ;
2019-06-29 14:33:55 +02:00
code = " static const int x = 42; \n "
" void f(){ int a = x; } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 42 ) ) ;
2019-04-21 06:54:32 +02:00
}
2017-09-15 15:58:19 +02:00
void valueFlowGlobalStaticVar ( ) {
const char * code ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { x=a; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { p = &x; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { x++; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { foo(x); } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
2018-03-18 19:53:33 +01:00
code = " static int x = 1; \n " // compound assignment
" void f() { \n "
" a = x; \n "
" } "
" void other() { x += b; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
2017-09-15 15:58:19 +02:00
}
2017-03-23 20:01:16 +01:00
void valueFlowInlineAssembly ( ) {
const char * code = " void f() { \n "
" int x = 42; \n "
" asm( \" \" ); \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 42 ) ) ;
}
2017-04-23 18:05:14 +02:00
2018-12-16 07:35:27 +01:00
void valueFlowSameExpression ( ) {
const char * code ;
code = " void f(int a) { \n "
" bool x = a == a; \n "
" bool b = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
code = " void f(int a) { \n "
" bool x = a != a; \n "
" bool b = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(int a) { \n "
" int x = a - a; \n "
" int b = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(float a) { \n "
" bool x = a == a; \n "
" bool b = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
}
2017-04-23 18:05:14 +02:00
void valueFlowUninit ( ) {
2017-04-24 18:27:16 +02:00
const char * code ;
2017-04-23 18:05:14 +02:00
std : : list < ValueFlow : : Value > values ;
2017-04-24 18:27:16 +02:00
code = " void f() { \n "
" int x; \n "
" switch (x) {} \n "
" } " ;
2017-04-23 18:05:14 +02:00
values = tokenValues ( code , " x ) " ) ;
2017-04-24 18:27:16 +02:00
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isUninitValue ( ) ) ;
code = " void f() { \n "
2018-08-27 11:09:09 +02:00
" const C *c; \n "
2017-04-24 18:27:16 +02:00
" if (c->x() == 4) {} \n "
" } " ;
values = tokenValues ( code , " c . " ) ;
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isUninitValue ( ) ) ;
2017-04-29 08:25:55 +02:00
2018-08-27 11:09:09 +02:00
code = " void f() { \n "
" C *c; \n "
" if (c->x() == 4) {} \n "
" } " ;
values = tokenValues ( code , " c . " ) ;
2019-08-16 07:48:54 +02:00
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isUninitValue ( ) ) ;
2018-08-27 11:09:09 +02:00
2017-04-29 08:25:55 +02:00
code = " void f() { \n "
" int **x; \n "
" y += 10; \n "
" x = dostuff(sizeof(*x)*y); \n "
" } " ;
ASSERT_EQUALS ( 0U , tokenValues ( code , " x ) " ) . size ( ) ) ;
2017-08-20 19:47:26 +02:00
// #8036
code = " void foo() { \n "
" int x; \n "
" f(x=3), return x+3; \n "
" } " ;
2020-02-16 16:02:22 +01:00
values = tokenValues ( code , " x + " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
// ASSERT_EQUALS(1U, values.size());
// ASSERT(values.front().isIntValue());
// ASSERT_EQUALS(3, values.front().intvalue);
2017-09-02 21:53:51 +02:00
// #8195
code = " void foo(std::istream &is) { \n "
" int x; \n "
" if (is >> x) { \n "
" a = x; \n "
" } \n "
" } " ;
values = tokenValues ( code , " x ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2017-09-14 22:49:47 +02:00
// return (#8173)
code = " int repeat() { \n "
" const char *n; \n "
" return((n=42) && *n == 'A'); \n "
" } " ;
values = tokenValues ( code , " n == " ) ;
ASSERT_EQUALS ( true , values . size ( ) ! = 1U | | ! values . front ( ) . isUninitValue ( ) ) ;
2017-11-06 10:28:07 +01:00
// #8233
code = " void foo() { \n "
" int x; \n "
" int y = 1; \n "
" if (y>1) \n "
" x = 1; \n "
" else \n "
" x = 1; \n "
" if (x>1) {} \n "
" } " ;
2020-02-16 16:02:22 +01:00
ASSERT_EQUALS ( true , testValueOfXKnown ( code , 8U , 1 ) ) ;
2018-02-11 22:14:44 +01:00
// #8348 - noreturn else
code = " int test_input_int(int a, int b) { \n "
" int x; \n "
" if (a == 1) \n "
" x = b; \n "
" else \n "
" abort(); \n "
" a = x + 1; \n "
" } \n " ;
values = tokenValues ( code , " x + " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2018-04-17 14:23:04 +02:00
// #8494 - overloaded operator &
code = " void f() { \n "
" int x; \n "
" a & x; \n "
" } " ;
values = tokenValues ( code , " x ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2018-07-25 22:59:54 +02:00
code = " void b(bool d, bool e) { \n "
" int c; \n "
" if (d) \n "
" c = 0; \n "
" if (e) \n "
" goto; \n "
" c++; \n "
" } \n " ;
values = tokenValues ( code , " c ++ ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
code = " void b(bool d, bool e) { \n "
" int c; \n "
" if (d) \n "
" c = 0; \n "
" if (e) \n "
" return; \n "
" c++; \n "
" } \n " ;
values = tokenValues ( code , " c ++ ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
code = " void b(bool d, bool e) { \n "
" int c; \n "
" if (d) \n "
" c = 0; \n "
" if (e) \n "
" exit(); \n "
" c++; \n "
" } \n " ;
values = tokenValues ( code , " c ++ ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
code = " void b(bool d, bool e) { \n "
" int c; \n "
" if (d) \n "
" c = 0; \n "
2019-08-08 07:46:47 +02:00
" else if (e) \n "
2018-07-25 22:59:54 +02:00
" c = 0; \n "
" c++; \n "
" } \n " ;
values = tokenValues ( code , " c ++ ; } " ) ;
2020-02-13 16:27:06 +01:00
TODO_ASSERT_EQUALS ( true , false , values . size ( ) = = 2 ) ;
// ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue());
// ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible());
// ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0);
2019-02-28 09:52:52 +01:00
2019-08-08 07:46:47 +02:00
code = " void b(bool d, bool e) { \n "
" int c; \n "
" if (d) \n "
" c = 0; \n "
" else if (!d) \n "
" c = 0; \n "
" c++; \n "
" } \n " ;
values = tokenValues ( code , " c ++ ; } " ) ;
ASSERT_EQUALS ( true , values . size ( ) = = 1 ) ;
// TODO: Value should be known
ASSERT_EQUALS ( true , values . back ( ) . isPossible ( ) ) ;
ASSERT_EQUALS ( true , values . back ( ) . intvalue = = 0 ) ;
2019-03-01 13:23:03 +01:00
code = " void f() { \n " // sqlite
2019-02-28 09:52:52 +01:00
" int szHdr; \n "
" idx = (A<0x80) ? (szHdr = 0) : dostuff(A, (int *)&(szHdr)); \n "
2019-03-01 13:23:03 +01:00
" d = szHdr; \n " // szHdr can be 0.
2019-02-28 09:52:52 +01:00
" } " ;
values = tokenValues ( code , " szHdr ; } " ) ;
TODO_ASSERT_EQUALS ( 1 , 0 , values . size ( ) ) ;
if ( values . size ( ) = = 1 ) {
ASSERT_EQUALS ( false , values . front ( ) . isUninitValue ( ) ) ;
}
2019-03-01 15:05:53 +01:00
2019-03-01 13:23:03 +01:00
code = " void f () { \n "
" int szHdr; \n "
" idx = ((aKey<0x80) ? ((szHdr)=aKey), 1 : sqlite3GetVarint32(&(szHdr))); \n "
" d = szHdr; \n "
" } " ;
values = tokenValues ( code , " szHdr ; } " ) ;
ASSERT_EQUALS ( 0 , values . size ( ) ) ;
2017-04-23 18:05:14 +02:00
}
2018-08-10 11:29:16 +02:00
2018-11-07 06:49:07 +01:00
void valueFlowTerminatingCond ( ) {
const char * code ;
// opposite condition
code = " void f(int i, int j) { \n "
" if (i == j) return; \n "
" if(i != j) {} \n "
" } \n " ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " != " ) . intvalue = = 1 ) ;
2018-11-07 06:49:07 +01:00
code = " void f(int i, int j) { \n "
" if (i == j) return; \n "
" i++; \n "
" if (i != j) {} \n "
" } \n " ;
ASSERT_EQUALS ( false , valueOfTok ( code , " != " ) . intvalue = = 1 ) ;
code = " void f(int i, int j, bool a) { \n "
" if (a) { \n "
" if (i == j) return; \n "
" } \n "
" if (i != j) {} \n "
" } \n " ;
ASSERT_EQUALS ( false , valueOfTok ( code , " != " ) . intvalue = = 1 ) ;
code = " void f(int i, int j, bool a) { \n "
" if (i != j) {} \n "
" if (i == j) return; \n "
" } \n " ;
ASSERT_EQUALS ( false , valueOfTok ( code , " != " ) . intvalue = = 1 ) ;
// same expression
code = " void f(int i, int j) { \n "
" if (i != j) return; \n "
" bool x = (i != j); \n "
" bool b = x; \n "
" } \n " ;
2019-08-05 07:18:06 +02:00
ASSERT_EQUALS ( true , testValueOfXKnown ( code , 4U , 0 ) ) ;
2018-11-07 06:49:07 +01:00
code = " void f(int i, int j) { \n "
" if (i != j) return; \n "
" i++; \n "
" bool x = (i != j); \n "
" bool b = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 5U , 0 ) ) ;
code = " void f(int i, int j, bool a) { \n "
" if (a) { \n "
" if (i != j) return; \n "
" } \n "
" bool x = (i != j); \n "
" bool b = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 6U , 0 ) ) ;
code = " void f(int i, int j, bool a) { \n "
" bool x = (i != j); \n "
" bool b = x; \n "
" if (i != j) return; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfXKnown ( code , 3U , 0 ) ) ;
code = " void f(int i, int j, bool b) { \n "
" if (i == j) { if(b) return; } \n "
" if(i != j) {} \n "
" } \n " ;
ASSERT_EQUALS ( false , valueOfTok ( code , " != " ) . intvalue = = 1 ) ;
2019-01-02 19:42:08 +01:00
code = " void foo() \n " // #8924
" { \n "
" if ( this->FileIndex >= 0 ) \n "
" return; \n "
" \n "
" this->FileIndex = 1 ; \n "
" if ( this->FileIndex < 0 ) {} \n "
" } " ;
ASSERT_EQUALS ( false , valueOfTok ( code , " < " ) . intvalue = = 1 ) ;
2018-11-07 06:49:07 +01:00
}
2018-08-10 22:18:38 +02:00
static std : : string isPossibleContainerSizeValue ( const std : : list < ValueFlow : : Value > & values , MathLib : : bigint i ) {
if ( values . size ( ) ! = 1 )
return " values.size(): " + std : : to_string ( values . size ( ) ) ;
if ( ! values . front ( ) . isContainerSizeValue ( ) )
return " ContainerSizeValue " ;
if ( ! values . front ( ) . isPossible ( ) )
return " Possible " ;
if ( values . front ( ) . intvalue ! = i )
return " intvalue: " + std : : to_string ( values . front ( ) . intvalue ) ;
return " " ;
}
2019-09-20 15:07:27 +02:00
static std : : string isImpossibleContainerSizeValue ( const std : : list < ValueFlow : : Value > & values , MathLib : : bigint i ) {
2019-09-20 15:06:37 +02:00
if ( values . size ( ) ! = 1 )
return " values.size(): " + std : : to_string ( values . size ( ) ) ;
if ( ! values . front ( ) . isContainerSizeValue ( ) )
return " ContainerSizeValue " ;
if ( ! values . front ( ) . isImpossible ( ) )
return " Impossible " ;
if ( values . front ( ) . intvalue ! = i )
return " intvalue: " + std : : to_string ( values . front ( ) . intvalue ) ;
return " " ;
}
2018-08-10 22:18:38 +02:00
static std : : string isKnownContainerSizeValue ( const std : : list < ValueFlow : : Value > & values , MathLib : : bigint i ) {
if ( values . size ( ) ! = 1 )
return " values.size(): " + std : : to_string ( values . size ( ) ) ;
if ( ! values . front ( ) . isContainerSizeValue ( ) )
return " ContainerSizeValue " ;
if ( ! values . front ( ) . isKnown ( ) )
return " Known " ;
if ( values . front ( ) . intvalue ! = i )
return " intvalue: " + std : : to_string ( values . front ( ) . intvalue ) ;
return " " ;
2018-08-10 22:06:23 +02:00
}
2018-08-10 11:29:16 +02:00
void valueFlowContainerSize ( ) {
const char * code ;
2018-08-10 22:06:23 +02:00
2018-08-10 11:29:16 +02:00
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
2019-01-06 12:21:47 +01:00
// condition
code = " void f(const std::list<int> &ints) { \n "
" if (!static_cast<bool>(ints.empty())) \n "
" ints.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " ints . front " ) . empty ( ) ) ;
2018-08-10 11:29:16 +02:00
// valueFlowContainerReverse
code = " void f(const std::list<int> &ints) { \n "
2018-08-11 13:49:42 +02:00
" ints.front(); \n " // <- container can be empty
2018-08-10 11:29:16 +02:00
" if (ints.empty()) {} \n "
" } " ;
2018-08-10 22:18:38 +02:00
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-10 11:29:16 +02:00
2018-08-10 11:53:56 +02:00
code = " void f(const std::list<int> &ints) { \n "
2018-08-11 13:49:42 +02:00
" ints.front(); \n " // <- container can be empty
2018-08-10 11:53:56 +02:00
" if (ints.size()==0) {} \n "
" } " ;
2018-08-10 22:18:38 +02:00
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-10 11:53:56 +02:00
2018-08-10 11:29:16 +02:00
code = " void f(std::list<int> ints) { \n "
2018-08-11 13:49:42 +02:00
" ints.front(); \n " // <- no container size
2018-08-10 11:29:16 +02:00
" ints.pop_back(); \n "
" if (ints.empty()) {} \n "
" } " ;
2018-08-10 22:06:23 +02:00
ASSERT ( tokenValues ( code , " ints . front " ) . empty ( ) ) ;
2018-08-10 21:42:13 +02:00
code = " void f(std::vector<int> v) { \n "
2018-08-11 13:49:42 +02:00
" v[10] = 0; \n " // <- container size can be 10
2018-08-10 21:42:13 +02:00
" if (v.size() == 10) {} \n "
" } " ;
2018-08-10 22:18:38 +02:00
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " v [ " ) , 10 ) ) ;
2018-08-10 21:42:13 +02:00
2018-09-04 20:28:48 +02:00
code = " void f(std::vector<std::string> params) { \n "
" switch(x) { \n "
" case CMD_RESPONSE: \n "
" if(y) { break; } \n "
" params[2]; \n " // <- container use
" break; \n "
" case CMD_DELETE: \n "
" if (params.size() < 2) { } \n " // <- condition
" break; \n "
" } \n "
" } " ;
ASSERT ( tokenValues ( code , " params [ 2 ] " ) . empty ( ) ) ;
2018-08-10 22:06:23 +02:00
// valueFlowContainerForward
code = " void f(const std::list<int> &ints) { \n "
" if (ints.empty()) {} \n "
2018-08-11 13:49:42 +02:00
" ints.front(); \n " // <- container can be empty
2018-08-10 22:06:23 +02:00
" } " ;
2018-08-10 22:18:38 +02:00
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-11 13:49:42 +02:00
code = " void f(const std::list<int> &ints) { \n "
" if (ints.empty()) { continue; } \n "
" ints.front(); \n " // <- no container size
" } " ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS ( " " , isImpossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-11 13:49:42 +02:00
2018-08-10 22:18:38 +02:00
code = " void f(const std::list<int> &ints) { \n "
2018-08-12 22:23:19 +02:00
" if (ints.empty()) { ints.push_back(0); } \n "
" ints.front(); \n " // <- container is not empty
" } " ;
ASSERT ( tokenValues ( code , " ints . front " ) . empty ( ) ) ;
code = " void f(const std::list<int> &ints) { \n "
2018-08-10 22:18:38 +02:00
" if (ints.empty()) { \n "
2018-08-11 13:49:42 +02:00
" ints.front(); \n " // <- container is empty
2018-08-10 22:18:38 +02:00
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-11 15:08:54 +02:00
2018-11-24 10:07:12 +01:00
code = " void f(const std::list<int> &ints) { \n "
" if (ints.size() == 3) { \n "
" ints.front(); \n " // <- container size is 3
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " ints . front " ) , 3 ) ) ;
code = " void f(const std::list<int> &ints) { \n "
" if (ints.size() <= 3) { \n "
" ints.front(); \n " // <- container size is 3
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 3 ) ) ;
code = " void f(const std::list<int> &ints) { \n "
" if (ints.size() >= 3) { \n "
" ints.front(); \n " // <- container size is 3
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 3 ) ) ;
code = " void f(const std::list<int> &ints) { \n "
" if (ints.size() < 3) { \n "
" ints.front(); \n " // <- container size is 2
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 2 ) ) ;
code = " void f(const std::list<int> &ints) { \n "
" if (ints.size() > 3) { \n "
" ints.front(); \n " // <- container size is 4
" } \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " ints . front " ) , 4 ) ) ;
2018-08-13 21:27:29 +02:00
code = " void f(const std::list<int> &ints) { \n "
" if (ints.empty() == false) { \n "
" ints.front(); \n " // <- container is not empty
" } \n "
" } " ;
ASSERT ( tokenValues ( code , " ints . front " ) . empty ( ) ) ;
2018-08-11 15:08:54 +02:00
code = " void f(const std::vector<int> &v) { \n "
" if (v.empty()) {} \n "
" if (!v.empty() && v[10]==0) {} \n " // <- no container size for 'v[10]'
" } " ;
ASSERT ( tokenValues ( code , " v [ " ) . empty ( ) ) ;
2018-08-12 14:39:29 +02:00
code = " void f() { \n "
2018-08-12 22:01:58 +02:00
" std::list<int> ints; \n " // No value => ints is empty
2018-08-12 14:39:29 +02:00
" ints.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " ints . front " ) , 0 ) ) ;
2018-08-12 22:01:58 +02:00
2018-08-27 13:49:47 +02:00
code = " void f() { \n "
" std::array<int,10> ints; \n " // Array size is 10
" ints.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " ints . front " ) , 10 ) ) ;
2018-08-12 22:01:58 +02:00
code = " void f() { \n "
2018-09-08 10:43:08 +02:00
" std::string s; \n "
" cin >> s; \n "
" s[0]; \n "
" } " ;
ASSERT ( tokenValues ( code , " s [ " ) . empty ( ) ) ;
code = " void f() { \n "
2018-11-02 18:28:32 +01:00
" std::string s = \" abc \" ; \n " // size of s is 3
2018-08-12 22:01:58 +02:00
" s.size(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " s . size " ) , 3 ) ) ;
2018-08-13 06:54:18 +02:00
2018-10-27 18:38:04 +02:00
code = " void f() { \n "
" std::string s= \" abc \" ; \n " // size of s is 3
" s += unknown; \n "
" s.size(); \n "
" } " ;
ASSERT ( tokenValues ( code , " s . size " ) . empty ( ) ) ;
code = " void f() { \n "
" std::string s= \" abc \" ; \n " // size of s is 3
" s += \" def \" ; \n " // size of s => 6
" s.size(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " s . size " ) , 6 ) ) ;
2018-10-28 19:14:00 +01:00
code = " void f(std::string s) { \n "
" if (s == \" hello \" ) \n "
" s[40] = c; \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " s [ " ) , 5 ) ) ;
code = " void f(std::string s) { \n "
" s[40] = c; \n "
" if (s == \" hello \" ) {} \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " s [ " ) , 5 ) ) ;
code = " void f(std::string s) { \n "
" if (s != \" hello \" ) {} \n "
" s[40] = c; \n "
" } " ;
ASSERT_EQUALS ( " " , isPossibleContainerSizeValue ( tokenValues ( code , " s [ " ) , 5 ) ) ;
code = " void f(std::string s) { \n "
" if (s != \" hello \" ) \n "
" s[40] = c; \n "
" } " ;
2019-09-20 15:06:37 +02:00
ASSERT_EQUALS ( " " , isImpossibleContainerSizeValue ( tokenValues ( code , " s [ " ) , 5 ) ) ;
2018-10-28 19:14:00 +01:00
2020-02-12 18:53:36 +01:00
code = " void f() { \n "
" static std::string s; \n "
" if (s.size() == 0) \n "
" s = x; \n "
" } " ;
ASSERT ( tokenValues ( code , " s . size " ) . empty ( ) ) ;
2018-11-02 20:10:40 +01:00
// valueFlowContainerForward, loop
code = " void f() { \n "
" std::stack<Token *> links; \n "
" while (!links.empty() || indentlevel) \n "
" links.push(tok); \n "
" } " ;
ASSERT ( tokenValues ( code , " links . empty " ) . empty ( ) ) ;
2018-08-13 06:54:18 +02:00
// valueFlowContainerForward, function call
code = " void f() { \n "
" std::list<int> x; \n "
" f(x); \n "
" x.front(); \n " // <- unknown container size
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
2018-08-21 06:32:33 +02:00
2018-09-02 14:08:34 +02:00
code = " void f() { \n " // #8689
" std::list<int> x; \n "
" f<ns::a>(x); \n "
" x.front(); \n " // <- unknown container size
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
2019-09-06 21:18:45 +02:00
code = " void g(std::list<int>&); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
code = " void g(std::list<int>*); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(&x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
2019-12-15 20:10:12 +01:00
code = " void g(std::list<int>* const); \n " // #9434
" void f() { \n "
" std::list<int> x; \n "
" g(&x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
2019-09-06 21:18:45 +02:00
code = " void g(const std::list<int>&); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(std::list<int>); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(int&); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x[0]); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(int&); \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x.back()); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(std::list<int>&) {} \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(std::list<int>& y) { y.push_back(1); } \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
code = " void g(std::list<int>*) {} \n "
" void f() { \n "
" std::list<int> x; \n "
" g(&x); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void g(std::list<int>* y) { y->push_back(1); } \n "
" void f() { \n "
" std::list<int> x; \n "
" g(&x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
code = " void h(std::list<int>&); \n "
" void g(std::list<int>& y) { h(y); } \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
code = " void h(const std::list<int>&); \n "
" void g(std::list<int>& y) { h(y); } \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " x . front " ) , 0 ) ) ;
code = " void h(const std::list<int>&); \n "
" void g(std::list<int>& y) { h(y); y.push_back(1); } \n "
" void f() { \n "
" std::list<int> x; \n "
" g(x); \n "
" x.front(); \n "
" } " ;
ASSERT ( tokenValues ( code , " x . front " ) . empty ( ) ) ;
2018-08-21 06:32:33 +02:00
code = " void f(std::vector<int> ints) { \n " // #8697
" if (ints.empty()) \n "
" abort() << 123; \n "
" ints[0] = 0; \n "
" } " ;
ASSERT ( tokenValues ( code , " ints [ " ) . empty ( ) ) ;
2019-10-18 08:21:07 +02:00
code = " struct A { \n " // forward, nested function call, #9424
" double getMessage( std::vector<unsigned char> *message ); \n "
" }; \n "
" \n "
" struct B { \n "
" A *a; \n "
" double getMessage( std::vector<unsigned char> *message ) { return a->getMessage( message ); } \n "
" }; \n "
" \n "
" void foo(B *ptr) { \n "
" std::vector<unsigned char> v; \n "
" ptr->getMessage (&v); \n "
" if (v.size () > 0) {} \n " // <- v has unknown size!
" } " ;
ASSERT_EQUALS ( 0U , tokenValues ( code , " v . size ( ) " ) . size ( ) ) ;
2019-12-14 19:04:19 +01:00
// if
code = " bool f(std::vector<int>&) { \n " // #9532
" return false; \n "
" } \n "
" int g() { \n "
" std::vector<int> v; \n "
" if (f(v) || v.empty()) \n "
" return 0; \n "
" return v[0]; \n "
" } \n " ;
ASSERT_EQUALS ( 0U , tokenValues ( code , " v [ 0 ] " ) . size ( ) ) ;
2018-11-02 18:28:32 +01:00
// container size => yields
code = " void f() { \n "
" std::string s = \" abcd \" ; \n "
" s.size(); \n "
" } " ;
ASSERT_EQUALS ( 4 , tokenValues ( code , " ( ) ; " ) . front ( ) . intvalue ) ;
code = " void f() { \n "
" std::string s; \n "
" s.empty(); \n "
" } " ;
ASSERT_EQUALS ( 1 , tokenValues ( code , " ( ) ; " ) . front ( ) . intvalue ) ;
// Calculations
code = " void f() { \n "
" std::string s = \" abcd \" ; \n "
" x = s + s; \n "
" } " ;
ASSERT_EQUALS ( " " , isKnownContainerSizeValue ( tokenValues ( code , " + " ) , 8 ) ) ;
2018-08-10 11:29:16 +02:00
}
2019-06-16 16:02:27 +02:00
void valueFlowDynamicBufferSize ( ) {
const char * code ;
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
LOAD_LIB_2 ( settings . library , " posix.cfg " ) ;
code = " void* f() { \n "
" void* x = malloc(10); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 10 , ValueFlow : : Value : : BUFFER_SIZE ) ) ;
code = " void* f() { \n "
" void* x = calloc(4, 5); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 20 , ValueFlow : : Value : : BUFFER_SIZE ) ) ;
code = " void* f() { \n "
" const char* y = \" abcd \" ; \n "
" const char* x = strdup(y); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 5 , ValueFlow : : Value : : BUFFER_SIZE ) ) ;
2019-07-05 12:44:52 +02:00
code = " void* f() { \n "
" void* y = malloc(10); \n "
" void* x = realloc(y, 20); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 20 , ValueFlow : : Value : : BUFFER_SIZE ) ) ;
code = " void* f() { \n "
" void* y = calloc(10, 4); \n "
" void* x = reallocarray(y, 20, 5); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 100 , ValueFlow : : Value : : BUFFER_SIZE ) ) ;
2019-06-16 16:02:27 +02:00
}
2019-07-10 16:59:05 +02:00
2019-07-24 10:57:19 +02:00
void valueFlowSafeFunctionParameterValues ( ) {
2019-07-10 16:59:05 +02:00
const char * code ;
std : : list < ValueFlow : : Value > values ;
Settings s ;
2019-07-24 11:39:18 +02:00
LOAD_LIB_2 ( s . library , " std.cfg " ) ;
2019-07-23 13:14:08 +02:00
s . safeChecks . classes = s . safeChecks . externalFunctions = s . safeChecks . internalFunctions = true ;
2019-07-10 16:59:05 +02:00
2019-07-13 07:29:06 +02:00
code = " short f(short x) { \n "
2019-07-10 16:59:05 +02:00
" return x + 0; \n "
" } " ;
values = tokenValues ( code , " + " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT_EQUALS ( - 0x8000 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 0x7fff , values . back ( ) . intvalue ) ;
2019-07-12 11:09:24 +02:00
2019-07-24 11:39:18 +02:00
code = " short f(std::string x) { \n "
" return x[10]; \n "
" } " ;
values = tokenValues ( code , " x [ " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 1000000 , values . back ( ) . intvalue ) ;
2019-07-24 12:08:56 +02:00
code = " int f(float x) { \n "
" return x; \n "
" } " ;
values = tokenValues ( code , " x ; " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT ( values . front ( ) . floatValue < - 1E20 ) ;
ASSERT ( values . back ( ) . floatValue > 1E20 ) ;
2019-07-24 15:08:04 +02:00
code = " short f(__cppcheck_low__(0) __cppcheck_high__(100) short x) { \n "
2019-07-12 11:09:24 +02:00
" return x + 0; \n "
" } " ;
values = tokenValues ( code , " + " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 100 , values . back ( ) . intvalue ) ;
2019-07-12 16:05:08 +02:00
2019-07-13 07:29:06 +02:00
code = " unsigned short f(unsigned short x) [[expects: x <= 100]] { \n "
2019-07-12 16:05:08 +02:00
" return x + 0; \n "
" } " ;
values = tokenValues ( code , " + " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 100 , values . back ( ) . intvalue ) ;
2019-07-10 16:59:05 +02:00
}
2019-07-10 20:00:21 +02:00
2019-07-11 16:05:34 +02:00
void valueFlowUnknownFunctionReturn ( ) {
2019-07-10 20:00:21 +02:00
const char * code ;
std : : list < ValueFlow : : Value > values ;
Settings s ;
2019-07-11 16:05:34 +02:00
LOAD_LIB_2 ( s . library , " std.cfg " ) ;
s . checkUnknownFunctionReturn . insert ( " rand " ) ;
2019-07-10 20:00:21 +02:00
code = " x = rand(); " ;
values = tokenValues ( code , " ( " , & s ) ;
ASSERT_EQUALS ( 2 , values . size ( ) ) ;
ASSERT_EQUALS ( INT_MIN , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( INT_MAX , values . back ( ) . intvalue ) ;
}
2019-08-12 12:58:53 +02:00
void valueFlowPointerAliasDeref ( ) {
const char * code ;
code = " int f() { \n "
" int a = 123; \n "
" int *p = &a; \n "
" int x = *p; \n "
" return x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 123 ) ) ;
}
Fix crashes in valueflow (#2236)
* Fix crashes in valueflow
http://cppcheck1.osuosl.org:8000/crash.html
For instance in http://cppcheck1.osuosl.org:8000/styx
```
==19651==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000001c (pc 0x556f21abc3df bp 0x7ffc140d2720 sp 0x7ffc140d2710 T0)
==19651==The signal is caused by a READ memory access.
==19651==Hint: address points to the zero page.
#0 0x556f21abc3de in Variable::isGlobal() const ../lib/symboldatabase.h:342
#1 0x556f221f801a in valueFlowForwardVariable ../lib/valueflow.cpp:2471
#2 0x556f22208130 in valueFlowForward ../lib/valueflow.cpp:3204
#3 0x556f221e9e14 in valueFlowReverse ../lib/valueflow.cpp:1892
#4 0x556f221f1a43 in valueFlowBeforeCondition ../lib/valueflow.cpp:2200
#5 0x556f2223dbb5 in ValueFlow::setValues(TokenList*, SymbolDatabase*, ErrorLogger*, Settings const*) ../lib/valueflow.cpp:6521
#6 0x556f220e5991 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/tokenize.cpp:2342
#7 0x556f21d8d066 in CppCheck::checkFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream&) ../lib/cppcheck.cpp:508
#8 0x556f21d84cd3 in CppCheck::check(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/cppcheck.cpp:192
#9 0x556f21a28796 in CppCheckExecutor::check_internal(CppCheck&, int, char const* const*) ../cli/cppcheckexecutor.cpp:884
#10 0x556f21a24be8 in CppCheckExecutor::check(int, char const* const*) ../cli/cppcheckexecutor.cpp:198
#11 0x556f22313063 in main ../cli/main.cpp:95
```
* Add test case for crash in valueflow
2019-10-16 20:54:07 +02:00
void valueFlowCrashIncompleteCode ( ) {
const char * code ;
code = " void SlopeFloor::setAttr(const Value &val) { \n "
" int x = val; \n "
" if (x >= -1) \n "
" state = x; \n "
" } \n " ;
valueOfTok ( code , " = " ) ;
2019-11-29 09:45:02 +01:00
code = " void a() { \n "
" auto b = [b = 0] { \n "
" if (b) { \n "
" } \n "
" }; \n "
" } \n " ;
valueOfTok ( code , " 0 " ) ;
Fix crashes in valueflow (#2236)
* Fix crashes in valueflow
http://cppcheck1.osuosl.org:8000/crash.html
For instance in http://cppcheck1.osuosl.org:8000/styx
```
==19651==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000001c (pc 0x556f21abc3df bp 0x7ffc140d2720 sp 0x7ffc140d2710 T0)
==19651==The signal is caused by a READ memory access.
==19651==Hint: address points to the zero page.
#0 0x556f21abc3de in Variable::isGlobal() const ../lib/symboldatabase.h:342
#1 0x556f221f801a in valueFlowForwardVariable ../lib/valueflow.cpp:2471
#2 0x556f22208130 in valueFlowForward ../lib/valueflow.cpp:3204
#3 0x556f221e9e14 in valueFlowReverse ../lib/valueflow.cpp:1892
#4 0x556f221f1a43 in valueFlowBeforeCondition ../lib/valueflow.cpp:2200
#5 0x556f2223dbb5 in ValueFlow::setValues(TokenList*, SymbolDatabase*, ErrorLogger*, Settings const*) ../lib/valueflow.cpp:6521
#6 0x556f220e5991 in Tokenizer::simplifyTokens1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/tokenize.cpp:2342
#7 0x556f21d8d066 in CppCheck::checkFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::istream&) ../lib/cppcheck.cpp:508
#8 0x556f21d84cd3 in CppCheck::check(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../lib/cppcheck.cpp:192
#9 0x556f21a28796 in CppCheckExecutor::check_internal(CppCheck&, int, char const* const*) ../cli/cppcheckexecutor.cpp:884
#10 0x556f21a24be8 in CppCheckExecutor::check(int, char const* const*) ../cli/cppcheckexecutor.cpp:198
#11 0x556f22313063 in main ../cli/main.cpp:95
```
* Add test case for crash in valueflow
2019-10-16 20:54:07 +02:00
}
2019-12-06 08:08:40 +01:00
void valueFlowCrash ( ) {
const char * code ;
code = " void f(int x) { \n "
" if (0 * (x > 2)) {} \n "
" } \n " ;
valueOfTok ( code , " x " ) ;
2019-12-29 08:23:58 +01:00
code = " const int& f(int, const int& y = 0); \n "
" const int& f(int, const int& y) { \n "
" return y; \n "
" } \n "
" const int& g(int x) { \n "
" const int& r = f(x); \n "
" return r; \n "
" } \n " ;
valueOfTok ( code , " 0 " ) ;
2020-03-20 07:16:05 +01:00
code = " void fa(int &colors) { \n "
" for (int i = 0; i != 6; ++i) {} \n "
" } \n "
" void fb(not_null<int*> parent, int &&colors2) { \n "
" dostuff(1); \n "
" } \n " ;
valueOfTok ( code , " x " ) ;
2020-03-22 10:12:53 +01:00
code = " void a() { \n "
" static int x = 0; \n "
" struct c { \n "
" c(c &&) { ++x; } \n "
" }; \n "
" } \n " ;
valueOfTok ( code , " x " ) ;
2020-04-11 13:56:53 +02:00
code = " void *foo(void *x); \n "
" void *foo(void *x) \n "
" { \n "
" if (!x) \n "
" yes: \n "
" return &&yes; \n "
" return x; \n "
" } \n " ;
valueOfTok ( code , " x " ) ;
2019-12-06 08:08:40 +01:00
}
2020-01-17 03:17:26 +01:00
2020-03-20 10:37:16 +01:00
void valueFlowHang ( ) {
const char * code ;
// #9659
code = " float arr1[4][4] = {0.0}; \n "
" float arr2[4][4] = {0.0}; \n "
" void f() { \n "
" if(arr1[0][0] == 0.0 && \n "
" arr1[0][1] == 0.0 && \n "
" arr1[0][2] == 0.0 && \n "
" arr1[0][3] == 0.0 && \n "
" arr1[1][0] == 0.0 && \n "
" arr1[1][1] == 0.0 && \n "
" arr1[1][2] == 0.0 && \n "
" arr1[1][3] == 0.0 && \n "
" arr1[2][0] == 0.0 && \n "
" arr1[2][1] == 0.0 && \n "
" arr1[2][2] == 0.0 && \n "
" arr1[2][3] == 0.0 && \n "
" arr1[3][0] == 0.0 && \n "
" arr1[3][1] == 0.0 && \n "
" arr1[3][2] == 0.0 && \n "
" arr1[3][3] == 0.0 && \n "
" arr2[0][0] == 0.0 && \n "
" arr2[0][1] == 0.0 && \n "
" arr2[0][2] == 0.0 && \n "
" arr2[0][3] == 0.0 && \n "
" arr2[1][0] == 0.0 && \n "
" arr2[1][1] == 0.0 && \n "
" arr2[1][2] == 0.0 && \n "
" arr2[1][3] == 0.0 && \n "
" arr2[2][0] == 0.0 && \n "
" arr2[2][1] == 0.0 && \n "
" arr2[2][2] == 0.0 && \n "
" arr2[2][3] == 0.0 && \n "
" arr2[3][0] == 0.0 && \n "
" arr2[3][1] == 0.0 && \n "
" arr2[3][2] == 0.0 && \n "
" arr2[3][3] == 0.0 \n "
" ) {} \n "
" } \n " ;
valueOfTok ( code , " x " ) ;
}
2020-01-17 03:17:26 +01:00
void valueFlowCrashConstructorInitialization ( ) { // #9577
const char * code ;
code = " void Error() \n "
" { \n "
" VfsPath path( \" \" ); \n "
" path = path / amtype; \n "
" size_t base = 0; \n "
" VfsPath standard( \" standard \" ); \n "
" if (path != standard) \n "
" { \n "
" } \n "
" } " ;
valueOfTok ( code , " path " ) ;
code = " void Error() \n "
" { \n "
" VfsPath path; \n "
" path = path / amtype; \n "
" size_t base = 0; \n "
" VfsPath standard( \" standard \" ); \n "
" if (path != standard) \n "
" { \n "
" } \n "
" } " ;
valueOfTok ( code , " path " ) ;
}
2014-01-04 20:57:02 +01:00
} ;
REGISTER_TEST ( TestValueFlow )