2019-09-17 21:00:59 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2022-02-05 11:45:17 +01:00
* Copyright ( C ) 2007 - 2022 Cppcheck team .
2019-09-17 21:00:59 +02: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/>.
*/
//---------------------------------------------------------------------------
# ifndef exprengineH
# define exprengineH
//---------------------------------------------------------------------------
2019-09-19 19:40:00 +02:00
# include "config.h"
2020-06-19 10:27:59 +02:00
# include "errortypes.h"
2019-09-19 19:40:00 +02:00
2022-01-27 19:03:20 +01:00
# include <algorithm>
2019-09-17 21:00:59 +02:00
# include <functional>
2022-01-27 19:03:20 +01:00
# include <iosfwd>
2019-09-17 21:00:59 +02:00
# include <map>
# include <memory>
# include <string>
# include <vector>
2022-01-27 19:03:20 +01:00
# include <utility>
2019-09-17 21:00:59 +02:00
class ErrorLogger ;
class Tokenizer ;
class Scope ;
class Settings ;
class Token ;
2019-09-25 18:33:21 +02:00
class Variable ;
2019-09-17 21:00:59 +02:00
2019-10-09 10:25:21 +02:00
# if defined(__GNUC__) && defined (__SIZEOF_INT128__)
2021-08-07 20:51:18 +02:00
typedef __int128_t int128_t ;
2019-09-17 21:00:59 +02:00
# else
2021-08-07 20:51:18 +02:00
typedef long long int128_t ;
2019-09-18 21:50:23 +02:00
# ifdef _MSC_VER
# pragma message(__FILE__ "(" _CRT_STRINGIZE(__LINE__) ")" ": warning: TODO No 128-bit integer type is available => Limited analysis of large integers...")
# else
2019-09-17 21:00:59 +02:00
# warning TODO No 128-bit integer type is available => Limited analysis of large integers
# endif
2019-09-18 21:50:23 +02:00
# endif
2019-09-17 21:00:59 +02:00
namespace ExprEngine {
std : : string str ( int128_t ) ;
// TODO we need to handle floats, containers, pointers, aliases and structs and stuff
2019-09-23 20:27:13 +02:00
enum class ValueType {
UninitValue ,
IntRange ,
FloatRange ,
2019-09-26 10:03:58 +02:00
ConditionalValue ,
2019-09-23 20:27:13 +02:00
ArrayValue ,
StringLiteralValue ,
StructValue ,
AddressOfValue ,
BinOpResult ,
2019-12-22 21:00:53 +01:00
IntegerTruncation ,
2020-12-05 11:47:57 +01:00
FunctionCallArgumentValues ,
2019-12-22 21:00:53 +01:00
BailoutValue
2019-09-23 20:27:13 +02:00
} ;
2019-09-17 21:00:59 +02:00
class Value ;
typedef std : : shared_ptr < Value > ValuePtr ;
2019-09-29 15:00:54 +02:00
class DataBase {
public :
2020-04-27 09:08:50 +02:00
explicit DataBase ( const std : : string & currentFunction , const Settings * settings )
: currentFunction ( currentFunction )
2021-08-07 20:51:18 +02:00
, settings ( settings ) { }
2019-09-29 15:00:54 +02:00
virtual std : : string getNewSymbolName ( ) = 0 ;
2020-04-27 09:08:50 +02:00
const std : : string currentFunction ;
2019-09-29 15:00:54 +02:00
const Settings * const settings ;
2020-06-27 22:11:12 +02:00
virtual bool isC ( ) const = 0 ;
virtual bool isCPP ( ) const = 0 ;
2020-06-19 10:27:59 +02:00
virtual void reportError ( const Token * tok ,
Severity : : SeverityType severity ,
const char id [ ] ,
const std : : string & text ,
CWE cwe ,
bool inconclusive ,
bool incomplete = false ,
2020-06-19 14:11:49 +02:00
const std : : string & functionName = std : : string ( ) ) = 0 ;
2020-06-19 10:27:59 +02:00
ErrorPath errorPath ;
2019-09-29 15:00:54 +02:00
} ;
2019-09-17 21:00:59 +02:00
class Value {
public :
2019-09-26 10:03:58 +02:00
Value ( const std : : string & name , const ValueType type ) : name ( name ) , type ( type ) { }
2019-09-17 21:00:59 +02:00
virtual ~ Value ( ) { }
2019-09-26 10:03:58 +02:00
virtual std : : string getRange ( ) const {
return name ;
}
virtual std : : string getSymbolicExpression ( ) const {
return name ;
}
2020-12-22 20:21:57 +01:00
virtual bool isEqual ( const DataBase * dataBase , int value ) const {
2019-10-02 21:47:00 +02:00
( void ) dataBase ;
2019-09-17 21:00:59 +02:00
( void ) value ;
return false ;
}
2020-12-22 20:21:57 +01:00
virtual bool isGreaterThan ( const DataBase * dataBase , int value ) const {
2019-10-08 20:13:25 +02:00
( void ) dataBase ;
( void ) value ;
return false ;
}
2020-12-22 20:21:57 +01:00
virtual bool isLessThan ( const DataBase * dataBase , int value ) const {
2019-10-08 20:13:25 +02:00
( void ) dataBase ;
( void ) value ;
return false ;
}
2022-01-03 12:46:33 +01:00
virtual bool isUninit ( const DataBase * dataBase ) const {
( void ) dataBase ;
2019-12-30 18:55:16 +01:00
return false ;
}
2019-10-08 20:13:25 +02:00
2019-09-17 21:00:59 +02:00
const std : : string name ;
2019-09-26 10:03:58 +02:00
ValueType type ;
2019-09-17 21:00:59 +02:00
} ;
2021-08-07 20:51:18 +02:00
class UninitValue : public Value {
2019-09-17 21:00:59 +02:00
public :
2019-09-26 10:03:58 +02:00
UninitValue ( ) : Value ( " ? " , ValueType : : UninitValue ) { }
2020-12-22 20:21:57 +01:00
bool isEqual ( const DataBase * dataBase , int value ) const OVERRIDE {
2020-01-09 19:40:03 +01:00
( void ) dataBase ;
( void ) value ;
return true ;
}
2022-01-03 12:46:33 +01:00
bool isUninit ( const DataBase * dataBase ) const OVERRIDE ;
2019-09-17 21:00:59 +02:00
} ;
class IntRange : public Value {
public :
IntRange ( const std : : string & name , int128_t minValue , int128_t maxValue )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : IntRange )
2019-09-17 21:00:59 +02:00
, minValue ( minValue )
2020-06-28 17:28:40 +02:00
, maxValue ( maxValue )
2021-08-07 20:51:18 +02:00
, loopScope ( nullptr ) { }
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-21 14:17:16 +02:00
if ( minValue = = maxValue )
return str ( minValue ) ;
return str ( minValue ) + " : " + str ( maxValue ) ;
2019-09-17 21:00:59 +02:00
}
2020-12-22 20:21:57 +01:00
bool isEqual ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isLessThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
2019-09-17 21:00:59 +02:00
int128_t minValue ;
int128_t maxValue ;
2020-06-28 17:28:40 +02:00
const Scope * loopScope ;
2019-09-17 21:00:59 +02:00
} ;
2019-09-22 21:14:20 +02:00
class FloatRange : public Value {
public :
FloatRange ( const std : : string & name , long double minValue , long double maxValue )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : FloatRange )
2019-09-22 21:14:20 +02:00
, minValue ( minValue )
2021-08-07 20:51:18 +02:00
, maxValue ( maxValue ) { }
2019-09-22 21:14:20 +02:00
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-22 21:14:20 +02:00
return std : : to_string ( minValue ) + " : " + std : : to_string ( maxValue ) ;
}
2020-12-22 20:21:57 +01:00
bool isEqual ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isLessThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
2019-12-30 19:47:18 +01:00
2019-09-22 21:14:20 +02:00
long double minValue ;
long double maxValue ;
} ;
2019-09-26 10:03:58 +02:00
class ConditionalValue : public Value {
public :
typedef std : : vector < std : : pair < ValuePtr , ValuePtr > > Vector ;
ConditionalValue ( const std : : string & name , const Vector & values ) : Value ( name , ValueType : : ConditionalValue ) , values ( values ) { }
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-26 10:03:58 +02:00
Vector values ;
} ;
2019-12-29 16:26:11 +01:00
// Array or pointer
2021-08-07 20:51:18 +02:00
class ArrayValue : public Value {
2019-09-17 21:00:59 +02:00
public :
2020-10-04 11:21:00 +02:00
enum { MAXSIZE = 0x7fffffff } ;
2019-09-17 21:00:59 +02:00
2019-12-29 16:26:11 +01:00
ArrayValue ( const std : : string & name , ValuePtr size , ValuePtr value , bool pointer , bool nullPointer , bool uninitPointer ) ;
2019-09-29 15:00:54 +02:00
ArrayValue ( DataBase * data , const Variable * var ) ;
2020-06-27 18:09:43 +02:00
ArrayValue ( const std : : string & name , const ArrayValue & arrayValue ) ;
2019-09-17 21:00:59 +02:00
2019-12-29 21:22:20 +01:00
std : : string getRange ( ) const OVERRIDE ;
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-17 21:00:59 +02:00
void assign ( ValuePtr index , ValuePtr value ) ;
2019-09-24 22:22:16 +02:00
void clear ( ) ;
2019-09-26 10:03:58 +02:00
ConditionalValue : : Vector read ( ValuePtr index ) const ;
2019-09-25 18:33:21 +02:00
2019-12-29 16:26:11 +01:00
bool pointer ;
bool nullPointer ;
bool uninitPointer ;
2019-09-25 18:33:21 +02:00
struct IndexAndValue {
ValuePtr index ;
ValuePtr value ;
} ;
std : : vector < IndexAndValue > data ;
2020-06-16 22:36:36 +02:00
std : : vector < ValuePtr > size ;
2019-09-17 21:00:59 +02:00
} ;
2021-08-07 20:51:18 +02:00
class StringLiteralValue : public Value {
2019-09-21 11:36:34 +02:00
public :
2019-09-26 10:03:58 +02:00
StringLiteralValue ( const std : : string & name , const std : : string & s ) : Value ( name , ValueType : : StringLiteralValue ) , string ( s ) { }
2019-09-21 11:36:34 +02:00
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-21 11:36:34 +02:00
return " \" " + string + " \" " ;
}
int size ( ) const {
return string . size ( ) ;
}
const std : : string string ;
} ;
2021-08-07 20:51:18 +02:00
class StructValue : public Value {
2019-09-17 21:00:59 +02:00
public :
2019-09-26 10:03:58 +02:00
explicit StructValue ( const std : : string & name ) : Value ( name , ValueType : : StructValue ) { }
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-26 19:39:12 +02:00
2020-12-14 12:32:30 +01:00
std : : string getRange ( ) const OVERRIDE {
return getSymbolicExpression ( ) ;
}
2020-05-10 22:16:58 +02:00
ValuePtr getValueOfMember ( const std : : string & n ) const {
auto it = member . find ( n ) ;
2019-09-17 21:00:59 +02:00
return ( it = = member . end ( ) ) ? ValuePtr ( ) : it - > second ;
}
2020-06-18 13:49:11 +02:00
2022-01-03 12:46:33 +01:00
std : : string getUninitStructMember ( const DataBase * dataBase ) const {
2020-06-18 13:49:11 +02:00
for ( auto memberNameValue : member ) {
2022-01-03 12:46:33 +01:00
if ( memberNameValue . second & & memberNameValue . second - > isUninit ( dataBase ) )
2020-06-18 13:49:11 +02:00
return memberNameValue . first ;
}
return std : : string ( ) ;
}
2019-09-17 21:00:59 +02:00
std : : map < std : : string , ValuePtr > member ;
} ;
2021-08-07 20:51:18 +02:00
class AddressOfValue : public Value {
2019-09-17 21:00:59 +02:00
public :
AddressOfValue ( const std : : string & name , int varId )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : AddressOfValue )
2019-09-17 21:00:59 +02:00
, varId ( varId )
{ }
2019-12-27 16:26:44 +01:00
std : : string getRange ( ) const OVERRIDE {
2019-09-26 10:03:58 +02:00
return " &@ " + std : : to_string ( varId ) ;
2019-09-17 21:00:59 +02:00
}
int varId ;
} ;
class BinOpResult : public Value {
public :
BinOpResult ( const std : : string & binop , ValuePtr op1 , ValuePtr op2 )
2019-09-27 14:20:17 +02:00
: Value ( getName ( binop , op1 , op2 ) , ValueType : : BinOpResult )
2019-09-17 21:00:59 +02:00
, binop ( binop )
, op1 ( op1 )
2021-08-07 20:51:18 +02:00
, op2 ( op2 ) { }
2019-09-17 21:00:59 +02:00
2020-12-22 20:21:57 +01:00
bool isEqual ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isGreaterThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
virtual bool isLessThan ( const DataBase * dataBase , int value ) const OVERRIDE ;
bool isTrue ( const DataBase * dataBase ) const ;
2019-10-08 20:13:25 +02:00
2019-10-02 21:47:00 +02:00
std : : string getExpr ( DataBase * dataBase ) const ;
2019-09-17 21:00:59 +02:00
std : : string binop ;
ValuePtr op1 ;
ValuePtr op2 ;
private :
2021-02-23 08:19:05 +01:00
static std : : string getName ( const std : : string & binop , ValuePtr op1 , ValuePtr op2 ) {
2019-09-27 14:20:17 +02:00
std : : string name1 = op1 ? op1 - > name : std : : string ( " null " ) ;
std : : string name2 = op2 ? op2 - > name : std : : string ( " null " ) ;
return " ( " + name1 + " ) " + binop + " ( " + name2 + " ) " ;
}
2019-09-17 21:00:59 +02:00
} ;
2019-09-23 20:27:13 +02:00
class IntegerTruncation : public Value {
public :
IntegerTruncation ( const std : : string & name , ValuePtr inputValue , int bits , char sign )
2019-09-26 10:03:58 +02:00
: Value ( name , ValueType : : IntegerTruncation )
2019-09-23 20:27:13 +02:00
, inputValue ( inputValue )
, bits ( bits )
2021-08-07 20:51:18 +02:00
, sign ( sign ) { }
2019-09-23 20:27:13 +02:00
2019-12-27 16:26:44 +01:00
std : : string getSymbolicExpression ( ) const OVERRIDE ;
2019-09-23 20:27:13 +02:00
ExprEngine : : ValuePtr inputValue ;
int bits ;
char sign ;
} ;
2021-08-07 20:51:18 +02:00
class FunctionCallArgumentValues : public Value {
2020-12-05 11:47:57 +01:00
public :
2020-12-05 12:41:01 +01:00
explicit FunctionCallArgumentValues ( const std : : vector < ExprEngine : : ValuePtr > & argValues )
2020-12-05 11:47:57 +01:00
: Value ( " argValues " , ValueType : : FunctionCallArgumentValues )
, argValues ( argValues )
{ }
const std : : vector < ExprEngine : : ValuePtr > argValues ;
} ;
2019-12-22 21:00:53 +01:00
class BailoutValue : public Value {
public :
BailoutValue ( ) : Value ( " bailout " , ValueType : : BailoutValue ) { }
2020-12-22 20:21:57 +01:00
bool isEqual ( const DataBase * /*dataBase*/ , int /*value*/ ) const OVERRIDE {
2020-01-12 10:42:20 +01:00
return true ;
}
2022-01-03 12:46:33 +01:00
bool isUninit ( const DataBase * dataBase ) const OVERRIDE {
( void ) dataBase ;
2019-12-22 21:00:53 +01:00
return true ;
}
} ;
2021-08-07 20:51:18 +02:00
typedef std : : function < void ( const Token * , const ExprEngine : : Value & , ExprEngine : : DataBase * ) > Callback ;
2019-09-17 21:00:59 +02:00
/** Execute all functions */
2020-04-28 17:16:13 +02:00
void CPPCHECKLIB executeAllFunctions ( ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings , const std : : vector < Callback > & callbacks , std : : ostream & report ) ;
void executeFunction ( const Scope * functionScope , ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings , const std : : vector < Callback > & callbacks , std : : ostream & report ) ;
2019-09-17 21:00:59 +02:00
void runChecks ( ErrorLogger * errorLogger , const Tokenizer * tokenizer , const Settings * settings ) ;
2020-05-27 19:37:07 +02:00
void dump ( ExprEngine : : ValuePtr val ) ;
2019-09-17 21:00:59 +02:00
}
# endif // exprengineH