2018-12-25 21:11:23 +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 .
2018-12-25 21:11:23 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "ctu.h"
# include "astutils.h"
# include "symboldatabase.h"
# include <tinyxml2.h>
2019-05-09 06:55:36 +02:00
# include <iterator> // back_inserter
2018-12-25 21:11:23 +01:00
//---------------------------------------------------------------------------
2018-12-30 11:55:39 +01:00
static const char ATTR_CALL_ID [ ] = " call-id " ;
static const char ATTR_CALL_FUNCNAME [ ] = " call-funcname " ;
static const char ATTR_CALL_ARGNR [ ] = " call-argnr " ;
static const char ATTR_CALL_ARGEXPR [ ] = " call-argexpr " ;
static const char ATTR_CALL_ARGVALUETYPE [ ] = " call-argvaluetype " ;
static const char ATTR_CALL_ARGVALUE [ ] = " call-argvalue " ;
2018-12-30 18:31:37 +01:00
static const char ATTR_WARNING [ ] = " warning " ;
2019-09-12 10:46:33 +02:00
static const char ATTR_LOC_FILENAME [ ] = " file " ;
static const char ATTR_LOC_LINENR [ ] = " line " ;
static const char ATTR_LOC_COLUMN [ ] = " col " ;
2018-12-30 18:31:37 +01:00
static const char ATTR_INFO [ ] = " info " ;
2018-12-30 11:55:39 +01:00
static const char ATTR_MY_ID [ ] = " my-id " ;
static const char ATTR_MY_ARGNR [ ] = " my-argnr " ;
static const char ATTR_MY_ARGNAME [ ] = " my-argname " ;
2019-03-23 08:36:10 +01:00
static const char ATTR_VALUE [ ] = " value " ;
2018-12-30 11:55:39 +01:00
2019-02-03 17:51:02 +01:00
int CTU : : maxCtuDepth = 2 ;
2018-12-30 11:55:39 +01:00
2018-12-25 21:11:23 +01:00
std : : string CTU : : getFunctionId ( const Tokenizer * tokenizer , const Function * function )
{
2019-08-18 12:19:05 +02:00
return tokenizer - > list . file ( function - > tokenDef ) + ' : ' + MathLib : : toString ( function - > tokenDef - > linenr ( ) ) + ' : ' + MathLib : : toString ( function - > tokenDef - > column ( ) ) ;
2018-12-25 21:11:23 +01:00
}
CTU : : FileInfo : : Location : : Location ( const Tokenizer * tokenizer , const Token * tok )
2019-01-12 18:29:08 +01:00
: fileName ( tokenizer - > list . file ( tok ) )
2019-09-12 10:46:33 +02:00
, lineNumber ( tok - > linenr ( ) )
, column ( tok - > column ( ) )
2018-12-25 21:11:23 +01:00
{
}
std : : string CTU : : FileInfo : : toString ( ) const
{
std : : ostringstream out ;
// Function calls..
for ( const CTU : : FileInfo : : FunctionCall & functionCall : functionCalls ) {
2018-12-30 11:55:39 +01:00
out < < functionCall . toXmlString ( ) ;
2018-12-25 21:11:23 +01:00
}
// Nested calls..
for ( const CTU : : FileInfo : : NestedCall & nestedCall : nestedCalls ) {
2018-12-30 11:55:39 +01:00
out < < nestedCall . toXmlString ( ) < < " \n " ;
2018-12-25 21:11:23 +01:00
}
return out . str ( ) ;
}
2018-12-30 11:55:39 +01:00
std : : string CTU : : FileInfo : : CallBase : : toBaseXmlString ( ) const
{
std : : ostringstream out ;
out < < " " < < ATTR_CALL_ID < < " = \" " < < callId < < " \" "
< < " " < < ATTR_CALL_FUNCNAME < < " = \" " < < callFunctionName < < " \" "
< < " " < < ATTR_CALL_ARGNR < < " = \" " < < callArgNr < < " \" "
< < " " < < ATTR_LOC_FILENAME < < " = \" " < < location . fileName < < " \" "
2019-09-12 10:46:33 +02:00
< < " " < < ATTR_LOC_LINENR < < " = \" " < < location . lineNumber < < " \" "
< < " " < < ATTR_LOC_COLUMN < < " = \" " < < location . column < < " \" " ;
2018-12-30 11:55:39 +01:00
return out . str ( ) ;
}
std : : string CTU : : FileInfo : : FunctionCall : : toXmlString ( ) const
{
std : : ostringstream out ;
out < < " <function-call "
< < toBaseXmlString ( )
< < " " < < ATTR_CALL_ARGEXPR < < " = \" " < < callArgumentExpression < < " \" "
< < " " < < ATTR_CALL_ARGVALUETYPE < < " = \" " < < callValueType < < " \" "
2018-12-30 18:31:37 +01:00
< < " " < < ATTR_CALL_ARGVALUE < < " = \" " < < callArgValue < < " \" " ;
if ( warning )
out < < " " < < ATTR_WARNING < < " = \" true \" " ;
if ( callValuePath . empty ( ) )
out < < " /> " ;
else {
out < < " > \n " ;
for ( const ErrorLogger : : ErrorMessage : : FileLocation & loc : callValuePath )
out < < " <path "
< < " " < < ATTR_LOC_FILENAME < < " = \" " < < loc . getfile ( ) < < " \" "
< < " " < < ATTR_LOC_LINENR < < " = \" " < < loc . line < < " \" "
2019-09-12 10:46:33 +02:00
< < " " < < ATTR_LOC_COLUMN < < " = \" " < < loc . column < < " \" "
2018-12-30 18:31:37 +01:00
< < " " < < ATTR_INFO < < " = \" " < < loc . getinfo ( ) < < " \" /> \n " ;
out < < " </function-call> " ;
}
2018-12-30 11:55:39 +01:00
return out . str ( ) ;
}
std : : string CTU : : FileInfo : : NestedCall : : toXmlString ( ) const
{
std : : ostringstream out ;
out < < " <function-call "
< < toBaseXmlString ( )
< < " " < < ATTR_MY_ID < < " = \" " < < myId < < " \" "
< < " " < < ATTR_MY_ARGNR < < " = \" " < < myArgNr < < " \" "
< < " /> " ;
return out . str ( ) ;
}
2018-12-25 21:11:23 +01:00
std : : string CTU : : FileInfo : : UnsafeUsage : : toString ( ) const
{
std : : ostringstream out ;
out < < " <unsafe-usage "
2018-12-30 11:55:39 +01:00
< < " " < < ATTR_MY_ID < < " = \" " < < myId < < ' \" '
< < " " < < ATTR_MY_ARGNR < < " = \" " < < myArgNr < < ' \" '
< < " " < < ATTR_MY_ARGNAME < < " = \" " < < myArgumentName < < ' \" '
< < " " < < ATTR_LOC_FILENAME < < " = \" " < < location . fileName < < ' \" '
2019-09-12 10:46:33 +02:00
< < " " < < ATTR_LOC_LINENR < < " = \" " < < location . lineNumber < < ' \" '
< < " " < < ATTR_LOC_COLUMN < < " = \" " < < location . column < < ' \" '
2019-03-23 08:36:10 +01:00
< < " " < < ATTR_VALUE < < " = \" " < < value < < " \" "
2018-12-25 21:11:23 +01:00
< < " /> \n " ;
return out . str ( ) ;
}
2018-12-26 15:56:10 +01:00
std : : string CTU : : toString ( const std : : list < CTU : : FileInfo : : UnsafeUsage > & unsafeUsage )
{
std : : ostringstream ret ;
for ( const CTU : : FileInfo : : UnsafeUsage & u : unsafeUsage )
ret < < u . toString ( ) ;
return ret . str ( ) ;
}
2018-12-30 11:55:39 +01:00
CTU : : FileInfo : : CallBase : : CallBase ( const Tokenizer * tokenizer , const Token * callToken )
: callId ( getFunctionId ( tokenizer , callToken - > function ( ) ) )
, callArgNr ( 0 )
, callFunctionName ( callToken - > next ( ) - > astOperand1 ( ) - > expressionString ( ) )
, location ( CTU : : FileInfo : : Location ( tokenizer , callToken ) )
{
}
CTU : : FileInfo : : NestedCall : : NestedCall ( const Tokenizer * tokenizer , const Function * myFunction , const Token * callToken )
: CallBase ( tokenizer , callToken )
, myId ( getFunctionId ( tokenizer , myFunction ) )
, myArgNr ( 0 )
{
}
static std : : string readAttrString ( const tinyxml2 : : XMLElement * e , const char * attr , bool * error )
{
const char * value = e - > Attribute ( attr ) ;
if ( ! value & & error )
* error = true ;
return value ? value : " " ;
}
static long long readAttrInt ( const tinyxml2 : : XMLElement * e , const char * attr , bool * error )
2018-12-25 21:11:23 +01:00
{
2018-12-30 11:55:39 +01:00
const char * value = e - > Attribute ( attr ) ;
if ( ! value & & error )
* error = true ;
return value ? std : : atoi ( value ) : 0 ;
}
2019-06-15 13:28:01 +02:00
bool CTU : : FileInfo : : CallBase : : loadBaseFromXml ( const tinyxml2 : : XMLElement * xmlElement )
2018-12-30 11:55:39 +01:00
{
bool error = false ;
2019-06-15 13:28:01 +02:00
callId = readAttrString ( xmlElement , ATTR_CALL_ID , & error ) ;
callFunctionName = readAttrString ( xmlElement , ATTR_CALL_FUNCNAME , & error ) ;
callArgNr = readAttrInt ( xmlElement , ATTR_CALL_ARGNR , & error ) ;
location . fileName = readAttrString ( xmlElement , ATTR_LOC_FILENAME , & error ) ;
2019-09-12 10:46:33 +02:00
location . lineNumber = readAttrInt ( xmlElement , ATTR_LOC_LINENR , & error ) ;
location . column = readAttrInt ( xmlElement , ATTR_LOC_COLUMN , & error ) ;
2018-12-30 11:55:39 +01:00
return ! error ;
}
2019-06-15 13:28:01 +02:00
bool CTU : : FileInfo : : FunctionCall : : loadFromXml ( const tinyxml2 : : XMLElement * xmlElement )
2018-12-30 11:55:39 +01:00
{
2019-06-15 13:28:01 +02:00
if ( ! loadBaseFromXml ( xmlElement ) )
2018-12-30 11:55:39 +01:00
return false ;
bool error = false ;
2019-06-15 13:28:01 +02:00
callArgumentExpression = readAttrString ( xmlElement , ATTR_CALL_ARGEXPR , & error ) ;
callValueType = ( ValueFlow : : Value : : ValueType ) readAttrInt ( xmlElement , ATTR_CALL_ARGVALUETYPE , & error ) ;
callArgValue = readAttrInt ( xmlElement , ATTR_CALL_ARGVALUE , & error ) ;
const char * w = xmlElement - > Attribute ( ATTR_WARNING ) ;
2018-12-30 18:31:37 +01:00
warning = w & & std : : strcmp ( w , " true " ) = = 0 ;
2019-06-15 13:28:01 +02:00
for ( const tinyxml2 : : XMLElement * e2 = xmlElement - > FirstChildElement ( ) ; ! error & & e2 ; e2 = e2 - > NextSiblingElement ( ) ) {
2018-12-30 18:31:37 +01:00
if ( std : : strcmp ( e2 - > Name ( ) , " path " ) ! = 0 )
continue ;
ErrorLogger : : ErrorMessage : : FileLocation loc ;
loc . setfile ( readAttrString ( e2 , ATTR_LOC_FILENAME , & error ) ) ;
loc . line = readAttrInt ( e2 , ATTR_LOC_LINENR , & error ) ;
2019-09-12 10:46:33 +02:00
loc . column = readAttrInt ( e2 , ATTR_LOC_COLUMN , & error ) ;
2018-12-30 18:31:37 +01:00
loc . setinfo ( readAttrString ( e2 , ATTR_INFO , & error ) ) ;
}
2018-12-30 11:55:39 +01:00
return ! error ;
}
2019-06-15 13:28:01 +02:00
bool CTU : : FileInfo : : NestedCall : : loadFromXml ( const tinyxml2 : : XMLElement * xmlElement )
2018-12-30 11:55:39 +01:00
{
2019-06-15 13:28:01 +02:00
if ( ! loadBaseFromXml ( xmlElement ) )
2018-12-30 11:55:39 +01:00
return false ;
bool error = false ;
2019-06-15 13:28:01 +02:00
myId = readAttrString ( xmlElement , ATTR_MY_ID , & error ) ;
myArgNr = readAttrInt ( xmlElement , ATTR_MY_ARGNR , & error ) ;
2018-12-30 11:55:39 +01:00
return ! error ;
2018-12-25 21:11:23 +01:00
}
void CTU : : FileInfo : : loadFromXml ( const tinyxml2 : : XMLElement * xmlElement )
{
for ( const tinyxml2 : : XMLElement * e = xmlElement - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
if ( std : : strcmp ( e - > Name ( ) , " function-call " ) = = 0 ) {
FunctionCall functionCall ;
2018-12-30 11:55:39 +01:00
if ( functionCall . loadFromXml ( e ) )
functionCalls . push_back ( functionCall ) ;
2018-12-25 21:11:23 +01:00
} else if ( std : : strcmp ( e - > Name ( ) , " nested-call " ) = = 0 ) {
NestedCall nestedCall ;
2018-12-30 11:55:39 +01:00
if ( nestedCall . loadFromXml ( e ) )
nestedCalls . push_back ( nestedCall ) ;
2018-12-25 21:11:23 +01:00
}
}
}
2018-12-30 16:23:25 +01:00
std : : map < std : : string , std : : list < const CTU : : FileInfo : : CallBase * > > CTU : : FileInfo : : getCallsMap ( ) const
2018-12-25 21:11:23 +01:00
{
2018-12-30 16:23:25 +01:00
std : : map < std : : string , std : : list < const CTU : : FileInfo : : CallBase * > > ret ;
2018-12-25 21:11:23 +01:00
for ( const CTU : : FileInfo : : NestedCall & nc : nestedCalls )
2018-12-30 16:23:25 +01:00
ret [ nc . callId ] . push_back ( & nc ) ;
for ( const CTU : : FileInfo : : FunctionCall & fc : functionCalls )
ret [ fc . callId ] . push_back ( & fc ) ;
2018-12-25 21:11:23 +01:00
return ret ;
}
std : : list < CTU : : FileInfo : : UnsafeUsage > CTU : : loadUnsafeUsageListFromXml ( const tinyxml2 : : XMLElement * xmlElement )
{
std : : list < CTU : : FileInfo : : UnsafeUsage > ret ;
for ( const tinyxml2 : : XMLElement * e = xmlElement - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
if ( std : : strcmp ( e - > Name ( ) , " unsafe-usage " ) ! = 0 )
continue ;
2018-12-30 11:55:39 +01:00
bool error = false ;
FileInfo : : UnsafeUsage unsafeUsage ;
unsafeUsage . myId = readAttrString ( e , ATTR_MY_ID , & error ) ;
unsafeUsage . myArgNr = readAttrInt ( e , ATTR_MY_ARGNR , & error ) ;
unsafeUsage . myArgumentName = readAttrString ( e , ATTR_MY_ARGNAME , & error ) ;
unsafeUsage . location . fileName = readAttrString ( e , ATTR_LOC_FILENAME , & error ) ;
2019-09-12 10:46:33 +02:00
unsafeUsage . location . lineNumber = readAttrInt ( e , ATTR_LOC_LINENR , & error ) ;
unsafeUsage . location . column = readAttrInt ( e , ATTR_LOC_COLUMN , & error ) ;
2019-03-23 08:36:10 +01:00
unsafeUsage . value = readAttrInt ( e , ATTR_VALUE , & error ) ;
2018-12-30 11:55:39 +01:00
if ( ! error )
ret . push_back ( unsafeUsage ) ;
2018-12-25 21:11:23 +01:00
}
return ret ;
}
static int isCallFunction ( const Scope * scope , int argnr , const Token * * tok )
{
const Variable * const argvar = scope - > function - > getArgumentVar ( argnr ) ;
if ( ! argvar - > isPointer ( ) )
return - 1 ;
for ( const Token * tok2 = scope - > bodyStart ; tok2 ! = scope - > bodyEnd ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > variable ( ) ! = argvar )
continue ;
if ( ! Token : : Match ( tok2 - > previous ( ) , " [(,] %var% [,)] " ) )
break ;
int argnr2 = 1 ;
const Token * prev = tok2 ;
while ( prev & & prev - > str ( ) ! = " ( " ) {
if ( Token : : Match ( prev , " ]|) " ) )
prev = prev - > link ( ) ;
else if ( prev - > str ( ) = = " , " )
+ + argnr2 ;
prev = prev - > previous ( ) ;
}
if ( ! prev | | ! Token : : Match ( prev - > previous ( ) , " %name% ( " ) )
break ;
if ( ! prev - > astOperand1 ( ) | | ! prev - > astOperand1 ( ) - > function ( ) )
break ;
* tok = prev - > previous ( ) ;
return argnr2 ;
}
return - 1 ;
}
CTU : : FileInfo * CTU : : getFileInfo ( const Tokenizer * tokenizer )
{
const SymbolDatabase * const symbolDatabase = tokenizer - > getSymbolDatabase ( ) ;
FileInfo * fileInfo = new FileInfo ;
// Parse all functions in TU
for ( const Scope & scope : symbolDatabase - > scopeList ) {
if ( ! scope . isExecutable ( ) | | scope . type ! = Scope : : eFunction | | ! scope . function )
continue ;
const Function * const function = scope . function ;
// source function calls
for ( const Token * tok = scope . bodyStart ; tok ! = scope . bodyEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) ! = " ( " | | ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
continue ;
if ( ! tok - > astOperand1 ( ) - > function ( ) )
continue ;
const std : : vector < const Token * > args ( getArguments ( tok - > previous ( ) ) ) ;
for ( int argnr = 0 ; argnr < args . size ( ) ; + + argnr ) {
const Token * argtok = args [ argnr ] ;
if ( ! argtok )
continue ;
2018-12-30 18:31:37 +01:00
for ( const ValueFlow : : Value & value : argtok - > values ( ) ) {
2019-03-23 08:36:10 +01:00
if ( ( ! value . isIntValue ( ) | | value . intvalue ! = 0 | | value . isInconclusive ( ) ) & & ! value . isBufferSizeValue ( ) )
2018-12-30 18:31:37 +01:00
continue ;
2019-09-20 15:06:37 +02:00
// Skip impossible values since they cannot be represented
if ( value . isImpossible ( ) )
continue ;
2018-12-30 22:17:21 +01:00
FileInfo : : FunctionCall functionCall ;
2019-03-23 08:36:10 +01:00
functionCall . callValueType = value . valueType ;
2018-12-30 11:55:39 +01:00
functionCall . callId = getFunctionId ( tokenizer , tok - > astOperand1 ( ) - > function ( ) ) ;
functionCall . callFunctionName = tok - > astOperand1 ( ) - > expressionString ( ) ;
2019-09-12 10:46:33 +02:00
functionCall . location = FileInfo : : Location ( tokenizer , tok ) ;
2018-12-30 11:55:39 +01:00
functionCall . callArgNr = argnr + 1 ;
functionCall . callArgumentExpression = argtok - > expressionString ( ) ;
2018-12-30 18:31:37 +01:00
functionCall . callArgValue = value . intvalue ;
2018-12-31 07:50:02 +01:00
functionCall . warning = ! value . errorSeverity ( ) ;
2018-12-30 18:31:37 +01:00
for ( const ErrorPathItem & i : value . errorPath ) {
ErrorLogger : : ErrorMessage : : FileLocation loc ;
loc . setfile ( tokenizer - > list . file ( i . first ) ) ;
loc . line = i . first - > linenr ( ) ;
2019-09-12 10:46:33 +02:00
loc . column = i . first - > column ( ) ;
2018-12-30 18:31:37 +01:00
loc . setinfo ( i . second ) ;
functionCall . callValuePath . push_back ( loc ) ;
}
2018-12-25 21:11:23 +01:00
fileInfo - > functionCalls . push_back ( functionCall ) ;
}
2019-03-23 11:20:35 +01:00
// array
if ( argtok - > variable ( ) & & argtok - > variable ( ) - > isArray ( ) & & argtok - > variable ( ) - > dimensions ( ) . size ( ) = = 1 & & argtok - > variable ( ) - > dimension ( 0 ) > 1 ) {
FileInfo : : FunctionCall functionCall ;
functionCall . callValueType = ValueFlow : : Value : : ValueType : : BUFFER_SIZE ;
functionCall . callId = getFunctionId ( tokenizer , tok - > astOperand1 ( ) - > function ( ) ) ;
functionCall . callFunctionName = tok - > astOperand1 ( ) - > expressionString ( ) ;
2019-09-12 10:46:33 +02:00
functionCall . location = FileInfo : : Location ( tokenizer , tok ) ;
2019-03-23 11:20:35 +01:00
functionCall . callArgNr = argnr + 1 ;
functionCall . callArgumentExpression = argtok - > expressionString ( ) ;
functionCall . callArgValue = argtok - > variable ( ) - > dimension ( 0 ) * argtok - > valueType ( ) - > typeSize ( * tokenizer - > getSettings ( ) ) ;
functionCall . warning = false ;
fileInfo - > functionCalls . push_back ( functionCall ) ;
}
2019-03-23 15:57:17 +01:00
// &var => buffer
if ( argtok - > isUnaryOp ( " & " ) & & argtok - > astOperand1 ( ) - > variable ( ) & & argtok - > astOperand1 ( ) - > valueType ( ) & & ! argtok - > astOperand1 ( ) - > variable ( ) - > isArray ( ) ) {
FileInfo : : FunctionCall functionCall ;
functionCall . callValueType = ValueFlow : : Value : : ValueType : : BUFFER_SIZE ;
functionCall . callId = getFunctionId ( tokenizer , tok - > astOperand1 ( ) - > function ( ) ) ;
functionCall . callFunctionName = tok - > astOperand1 ( ) - > expressionString ( ) ;
2019-09-12 10:46:33 +02:00
functionCall . location = FileInfo : : Location ( tokenizer , tok ) ;
2019-03-23 15:57:17 +01:00
functionCall . callArgNr = argnr + 1 ;
functionCall . callArgumentExpression = argtok - > expressionString ( ) ;
functionCall . callArgValue = argtok - > astOperand1 ( ) - > valueType ( ) - > typeSize ( * tokenizer - > getSettings ( ) ) ;
functionCall . warning = false ;
fileInfo - > functionCalls . push_back ( functionCall ) ;
}
2018-12-25 21:11:23 +01:00
// pointer to uninitialized data..
if ( ! argtok - > isUnaryOp ( " & " ) )
continue ;
argtok = argtok - > astOperand1 ( ) ;
if ( ! argtok | | ! argtok - > valueType ( ) | | argtok - > valueType ( ) - > pointer ! = 0 )
continue ;
if ( argtok - > values ( ) . size ( ) ! = 1U )
continue ;
const ValueFlow : : Value & v = argtok - > values ( ) . front ( ) ;
2019-07-10 14:04:56 +02:00
if ( v . valueType = = ValueFlow : : Value : : ValueType : : UNINIT & & ! v . isInconclusive ( ) ) {
2018-12-30 22:17:21 +01:00
FileInfo : : FunctionCall functionCall ;
2019-07-10 14:04:56 +02:00
functionCall . callValueType = ValueFlow : : Value : : ValueType : : UNINIT ;
2018-12-30 11:55:39 +01:00
functionCall . callId = getFunctionId ( tokenizer , tok - > astOperand1 ( ) - > function ( ) ) ;
functionCall . callFunctionName = tok - > astOperand1 ( ) - > expressionString ( ) ;
2019-09-12 10:46:33 +02:00
functionCall . location = FileInfo : : Location ( tokenizer , tok ) ;
2018-12-30 11:55:39 +01:00
functionCall . callArgNr = argnr + 1 ;
functionCall . callArgValue = 0 ;
functionCall . callArgumentExpression = argtok - > expressionString ( ) ;
2018-12-30 18:31:37 +01:00
functionCall . warning = false ;
2018-12-25 21:11:23 +01:00
fileInfo - > functionCalls . push_back ( functionCall ) ;
continue ;
}
}
}
// Nested function calls
for ( int argnr = 0 ; argnr < function - > argCount ( ) ; + + argnr ) {
const Token * tok ;
2018-12-30 22:17:21 +01:00
const int argnr2 = isCallFunction ( & scope , argnr , & tok ) ;
2018-12-25 21:11:23 +01:00
if ( argnr2 > 0 ) {
2018-12-30 11:55:39 +01:00
FileInfo : : NestedCall nestedCall ( tokenizer , function , tok ) ;
nestedCall . myArgNr = argnr + 1 ;
nestedCall . callArgNr = argnr2 ;
2018-12-25 21:11:23 +01:00
fileInfo - > nestedCalls . push_back ( nestedCall ) ;
}
}
}
return fileInfo ;
}
2018-12-26 11:36:26 +01:00
2019-03-23 08:36:10 +01:00
static std : : list < std : : pair < const Token * , MathLib : : bigint > > getUnsafeFunction ( const Tokenizer * tokenizer , const Settings * settings , const Scope * scope , int argnr , const Check * check , bool ( * isUnsafeUsage ) ( const Check * check , const Token * argtok , MathLib : : bigint * value ) )
2018-12-26 19:17:49 +01:00
{
2019-03-23 08:36:10 +01:00
std : : list < std : : pair < const Token * , MathLib : : bigint > > ret ;
2018-12-26 19:17:49 +01:00
const Variable * const argvar = scope - > function - > getArgumentVar ( argnr ) ;
if ( ! argvar - > isPointer ( ) )
2019-03-23 08:36:10 +01:00
return ret ;
2018-12-26 19:17:49 +01:00
for ( const Token * tok2 = scope - > bodyStart ; tok2 ! = scope - > bodyEnd ; tok2 = tok2 - > next ( ) ) {
2018-12-31 08:24:39 +01:00
if ( Token : : Match ( tok2 , " )|else { " ) ) {
2018-12-26 19:17:49 +01:00
tok2 = tok2 - > linkAt ( 1 ) ;
if ( Token : : findmatch ( tok2 - > link ( ) , " return|throw " , tok2 ) )
2019-03-23 08:36:10 +01:00
return ret ;
2018-12-26 19:17:49 +01:00
if ( isVariableChanged ( tok2 - > link ( ) , tok2 , argvar - > declarationId ( ) , false , settings , tokenizer - > isCPP ( ) ) )
2019-03-23 08:36:10 +01:00
return ret ;
2018-12-26 19:17:49 +01:00
}
2018-12-31 08:16:21 +01:00
if ( Token : : Match ( tok2 , " %oror%|&&|? " ) ) {
tok2 = tok2 - > findExpressionStartEndTokens ( ) . second ;
continue ;
}
2018-12-26 19:17:49 +01:00
if ( tok2 - > variable ( ) ! = argvar )
continue ;
2019-03-23 08:36:10 +01:00
MathLib : : bigint value = 0 ;
if ( ! isUnsafeUsage ( check , tok2 , & value ) )
return ret ; // TODO: Is this a read? then continue..
ret . emplace_back ( tok2 , value ) ;
return ret ;
2018-12-26 19:17:49 +01:00
}
2019-03-23 08:36:10 +01:00
return ret ;
2018-12-26 19:17:49 +01:00
}
2019-03-23 08:36:10 +01:00
std : : list < CTU : : FileInfo : : UnsafeUsage > CTU : : getUnsafeUsage ( const Tokenizer * tokenizer , const Settings * settings , const Check * check , bool ( * isUnsafeUsage ) ( const Check * check , const Token * argtok , MathLib : : bigint * _value ) )
2018-12-26 19:17:49 +01:00
{
std : : list < CTU : : FileInfo : : UnsafeUsage > unsafeUsage ;
// Parse all functions in TU
const SymbolDatabase * const symbolDatabase = tokenizer - > getSymbolDatabase ( ) ;
for ( const Scope & scope : symbolDatabase - > scopeList ) {
if ( ! scope . isExecutable ( ) | | scope . type ! = Scope : : eFunction | | ! scope . function )
continue ;
const Function * const function = scope . function ;
// "Unsafe" functions unconditionally reads data before it is written..
for ( int argnr = 0 ; argnr < function - > argCount ( ) ; + + argnr ) {
2019-03-23 08:36:10 +01:00
for ( const std : : pair < const Token * , MathLib : : bigint > & v : getUnsafeFunction ( tokenizer , settings , & scope , argnr , check , isUnsafeUsage ) ) {
const Token * tok = v . first ;
MathLib : : bigint value = v . second ;
unsafeUsage . emplace_back ( CTU : : getFunctionId ( tokenizer , function ) , argnr + 1 , tok - > str ( ) , CTU : : FileInfo : : Location ( tokenizer , tok ) , value ) ;
}
2018-12-26 19:17:49 +01:00
}
}
return unsafeUsage ;
}
2018-12-26 11:36:26 +01:00
2018-12-30 16:23:25 +01:00
static bool findPath ( const std : : string & callId ,
2019-07-14 12:22:33 +02:00
nonneg int callArgNr ,
2019-03-23 08:36:10 +01:00
MathLib : : bigint unsafeValue ,
2018-12-30 16:23:25 +01:00
CTU : : FileInfo : : InvalidValueType invalidValue ,
const std : : map < std : : string , std : : list < const CTU : : FileInfo : : CallBase * > > & callsMap ,
const CTU : : FileInfo : : CallBase * path [ 10 ] ,
2018-12-30 18:31:37 +01:00
int index ,
bool warning )
2018-12-26 11:36:26 +01:00
{
2019-02-03 17:51:02 +01:00
if ( index > = CTU : : maxCtuDepth | | index > = 10 )
2018-12-30 16:23:25 +01:00
return false ;
2018-12-26 11:36:26 +01:00
2018-12-30 16:23:25 +01:00
const std : : map < std : : string , std : : list < const CTU : : FileInfo : : CallBase * > > : : const_iterator it = callsMap . find ( callId ) ;
if ( it = = callsMap . end ( ) )
2018-12-26 11:36:26 +01:00
return false ;
2018-12-30 16:23:25 +01:00
for ( const CTU : : FileInfo : : CallBase * c : it - > second ) {
if ( c - > callArgNr ! = callArgNr )
continue ;
const CTU : : FileInfo : : FunctionCall * functionCall = dynamic_cast < const CTU : : FileInfo : : FunctionCall * > ( c ) ;
if ( functionCall ) {
2018-12-30 18:31:37 +01:00
if ( ! warning & & functionCall - > warning )
continue ;
2018-12-30 16:23:25 +01:00
switch ( invalidValue ) {
case CTU : : FileInfo : : InvalidValueType : : null :
2019-07-10 14:04:56 +02:00
if ( functionCall - > callValueType ! = ValueFlow : : Value : : ValueType : : INT | | functionCall - > callArgValue ! = 0 )
2018-12-30 16:23:25 +01:00
continue ;
break ;
case CTU : : FileInfo : : InvalidValueType : : uninit :
2019-07-10 14:04:56 +02:00
if ( functionCall - > callValueType ! = ValueFlow : : Value : : ValueType : : UNINIT )
2018-12-30 16:23:25 +01:00
continue ;
break ;
2019-03-23 08:36:10 +01:00
case CTU : : FileInfo : : InvalidValueType : : bufferOverflow :
2019-07-10 14:04:56 +02:00
if ( functionCall - > callValueType ! = ValueFlow : : Value : : ValueType : : BUFFER_SIZE )
2019-03-23 08:36:10 +01:00
continue ;
if ( unsafeValue < 0 | | unsafeValue > = functionCall - > callArgValue )
break ;
continue ;
2018-12-30 16:23:25 +01:00
} ;
path [ index ] = functionCall ;
return true ;
}
const CTU : : FileInfo : : NestedCall * nestedCall = dynamic_cast < const CTU : : FileInfo : : NestedCall * > ( c ) ;
if ( ! nestedCall )
continue ;
2019-03-23 08:36:10 +01:00
if ( findPath ( nestedCall - > myId , nestedCall - > myArgNr , unsafeValue , invalidValue , callsMap , path , index + 1 , warning ) ) {
2018-12-30 16:23:25 +01:00
path [ index ] = nestedCall ;
2018-12-26 11:36:26 +01:00
return true ;
2018-12-30 16:23:25 +01:00
}
2018-12-26 11:36:26 +01:00
}
return false ;
}
2018-12-26 15:56:10 +01:00
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > CTU : : FileInfo : : getErrorPath ( InvalidValueType invalidValue ,
2018-12-26 11:36:26 +01:00
const CTU : : FileInfo : : UnsafeUsage & unsafeUsage ,
2018-12-30 16:23:25 +01:00
const std : : map < std : : string , std : : list < const CTU : : FileInfo : : CallBase * > > & callsMap ,
2018-12-26 15:56:10 +01:00
const char info [ ] ,
2018-12-30 18:31:37 +01:00
const FunctionCall * * const functionCallPtr ,
bool warning ) const
2018-12-26 11:36:26 +01:00
{
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locationList ;
2019-06-30 21:39:22 +02:00
const CTU : : FileInfo : : CallBase * path [ 10 ] = { nullptr } ;
2018-12-26 11:36:26 +01:00
2019-03-23 08:36:10 +01:00
if ( ! findPath ( unsafeUsage . myId , unsafeUsage . myArgNr , unsafeUsage . value , invalidValue , callsMap , path , 0 , warning ) )
2018-12-30 16:23:25 +01:00
return locationList ;
2018-12-26 15:56:10 +01:00
2018-12-30 16:23:25 +01:00
const std : : string value1 = ( invalidValue = = InvalidValueType : : null ) ? " null " : " uninitialized " ;
2018-12-26 11:36:26 +01:00
2018-12-30 16:23:25 +01:00
for ( int index = 9 ; index > = 0 ; index - - ) {
if ( ! path [ index ] )
continue ;
2018-12-26 11:36:26 +01:00
2018-12-30 18:31:37 +01:00
const CTU : : FileInfo : : FunctionCall * functionCall = dynamic_cast < const CTU : : FileInfo : : FunctionCall * > ( path [ index ] ) ;
if ( functionCall ) {
if ( functionCallPtr )
* functionCallPtr = functionCall ;
2019-05-08 20:23:32 +02:00
std : : copy ( functionCall - > callValuePath . cbegin ( ) , functionCall - > callValuePath . cend ( ) , std : : back_inserter ( locationList ) ) ;
2018-12-30 18:31:37 +01:00
}
2018-12-26 15:56:10 +01:00
2019-09-12 19:20:13 +02:00
ErrorLogger : : ErrorMessage : : FileLocation fileLoc ( path [ index ] - > location . fileName , path [ index ] - > location . lineNumber , path [ index ] - > location . column ) ;
2018-12-30 16:23:25 +01:00
fileLoc . setinfo ( " Calling function " + path [ index ] - > callFunctionName + " , " + MathLib : : toString ( path [ index ] - > callArgNr ) + getOrdinalText ( path [ index ] - > callArgNr ) + " argument is " + value1 ) ;
locationList . push_back ( fileLoc ) ;
2018-12-26 15:56:10 +01:00
}
2018-12-26 11:36:26 +01:00
2019-09-12 19:20:13 +02:00
ErrorLogger : : ErrorMessage : : FileLocation fileLoc2 ( unsafeUsage . location . fileName , unsafeUsage . location . lineNumber , unsafeUsage . location . column ) ;
2018-12-30 16:23:25 +01:00
fileLoc2 . setinfo ( replaceStr ( info , " ARG " , unsafeUsage . myArgumentName ) ) ;
locationList . push_back ( fileLoc2 ) ;
2018-12-26 11:36:26 +01:00
return locationList ;
}