cppcheck/lib/exprengine.h

349 lines
11 KiB
C++

/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2022 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#ifndef exprengineH
#define exprengineH
//---------------------------------------------------------------------------
#include "config.h"
#include "errortypes.h"
#include <algorithm>
#include <functional>
#include <iosfwd>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <utility>
class ErrorLogger;
class Tokenizer;
class Scope;
class Settings;
class Token;
class Variable;
#if defined(__GNUC__) && defined (__SIZEOF_INT128__)
typedef __int128_t int128_t;
#else
typedef long long int128_t;
#ifdef _MSC_VER
#pragma message(__FILE__ "(" _CRT_STRINGIZE(__LINE__) ")" ": warning: TODO No 128-bit integer type is available => Limited analysis of large integers...")
#else
#warning TODO No 128-bit integer type is available => Limited analysis of large integers
#endif
#endif
namespace ExprEngine {
std::string str(int128_t);
// TODO we need to handle floats, containers, pointers, aliases and structs and stuff
enum class ValueType {
UninitValue,
IntRange,
FloatRange,
ConditionalValue,
ArrayValue,
StringLiteralValue,
StructValue,
AddressOfValue,
BinOpResult,
IntegerTruncation,
FunctionCallArgumentValues,
BailoutValue
};
class Value;
typedef std::shared_ptr<Value> ValuePtr;
class DataBase {
public:
explicit DataBase(const std::string &currentFunction, const Settings *settings)
: currentFunction(currentFunction)
, settings(settings) {}
virtual std::string getNewSymbolName() = 0;
const std::string currentFunction;
const Settings * const settings;
virtual bool isC() const = 0;
virtual bool isCPP() const = 0;
virtual void reportError(const Token *tok,
Severity::SeverityType severity,
const char id[],
const std::string &text,
CWE cwe,
bool inconclusive,
bool incomplete=false,
const std::string &functionName = std::string()) = 0;
ErrorPath errorPath;
};
class Value {
public:
Value(const std::string &name, const ValueType type) : name(name), type(type) {}
virtual ~Value() {}
virtual std::string getRange() const {
return name;
}
virtual std::string getSymbolicExpression() const {
return name;
}
virtual bool isEqual(const DataBase *dataBase, int value) const {
(void)dataBase;
(void)value;
return false;
}
virtual bool isGreaterThan(const DataBase *dataBase, int value) const {
(void)dataBase;
(void)value;
return false;
}
virtual bool isLessThan(const DataBase *dataBase, int value) const {
(void)dataBase;
(void)value;
return false;
}
virtual bool isUninit(const DataBase *dataBase) const {
(void)dataBase;
return false;
}
const std::string name;
ValueType type;
};
class UninitValue : public Value {
public:
UninitValue() : Value("?", ValueType::UninitValue) {}
bool isEqual(const DataBase *dataBase, int value) const OVERRIDE {
(void)dataBase;
(void)value;
return true;
}
bool isUninit(const DataBase *dataBase) const OVERRIDE;
};
class IntRange : public Value {
public:
IntRange(const std::string &name, int128_t minValue, int128_t maxValue)
: Value(name, ValueType::IntRange)
, minValue(minValue)
, maxValue(maxValue)
, loopScope(nullptr) {}
std::string getRange() const OVERRIDE {
if (minValue == maxValue)
return str(minValue);
return str(minValue) + ":" + str(maxValue);
}
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;
int128_t minValue;
int128_t maxValue;
const Scope *loopScope;
};
class FloatRange : public Value {
public:
FloatRange(const std::string &name, long double minValue, long double maxValue)
: Value(name, ValueType::FloatRange)
, minValue(minValue)
, maxValue(maxValue) {}
std::string getRange() const OVERRIDE {
return std::to_string(minValue) + ":" + std::to_string(maxValue);
}
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;
long double minValue;
long double maxValue;
};
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) {}
std::string getSymbolicExpression() const OVERRIDE;
Vector values;
};
// Array or pointer
class ArrayValue : public Value {
public:
enum { MAXSIZE = 0x7fffffff };
ArrayValue(const std::string &name, ValuePtr size, ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer);
ArrayValue(DataBase *data, const Variable *var);
ArrayValue(const std::string &name, const ArrayValue &arrayValue);
std::string getRange() const OVERRIDE;
std::string getSymbolicExpression() const OVERRIDE;
void assign(ValuePtr index, ValuePtr value);
void clear();
ConditionalValue::Vector read(ValuePtr index) const;
bool pointer;
bool nullPointer;
bool uninitPointer;
struct IndexAndValue {
ValuePtr index;
ValuePtr value;
};
std::vector<IndexAndValue> data;
std::vector<ValuePtr> size;
};
class StringLiteralValue : public Value {
public:
StringLiteralValue(const std::string &name, const std::string &s) : Value(name, ValueType::StringLiteralValue), string(s) {}
std::string getRange() const OVERRIDE {
return "\"" + string + "\"";
}
int size() const {
return string.size();
}
const std::string string;
};
class StructValue : public Value {
public:
explicit StructValue(const std::string &name) : Value(name, ValueType::StructValue) {}
std::string getSymbolicExpression() const OVERRIDE;
std::string getRange() const OVERRIDE {
return getSymbolicExpression();
}
ValuePtr getValueOfMember(const std::string &n) const {
auto it = member.find(n);
return (it == member.end()) ? ValuePtr() : it->second;
}
std::string getUninitStructMember(const DataBase *dataBase) const {
for (auto memberNameValue: member) {
if (memberNameValue.second && memberNameValue.second->isUninit(dataBase))
return memberNameValue.first;
}
return std::string();
}
std::map<std::string, ValuePtr> member;
};
class AddressOfValue : public Value {
public:
AddressOfValue(const std::string &name, int varId)
: Value(name, ValueType::AddressOfValue)
, varId(varId)
{}
std::string getRange() const OVERRIDE {
return "&@" + std::to_string(varId);
}
int varId;
};
class BinOpResult : public Value {
public:
BinOpResult(const std::string &binop, ValuePtr op1, ValuePtr op2)
: Value(getName(binop, op1, op2), ValueType::BinOpResult)
, binop(binop)
, op1(op1)
, op2(op2) {}
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;
std::string getExpr(DataBase *dataBase) const;
std::string binop;
ValuePtr op1;
ValuePtr op2;
private:
static std::string getName(const std::string& binop, ValuePtr op1, ValuePtr op2) {
std::string name1 = op1 ? op1->name : std::string("null");
std::string name2 = op2 ? op2->name : std::string("null");
return "(" + name1 + ")" + binop + "(" + name2 + ")";
}
};
class IntegerTruncation : public Value {
public:
IntegerTruncation(const std::string &name, ValuePtr inputValue, int bits, char sign)
: Value(name, ValueType::IntegerTruncation)
, inputValue(inputValue)
, bits(bits)
, sign(sign) {}
std::string getSymbolicExpression() const OVERRIDE;
ExprEngine::ValuePtr inputValue;
int bits;
char sign;
};
class FunctionCallArgumentValues : public Value {
public:
explicit FunctionCallArgumentValues(const std::vector<ExprEngine::ValuePtr> &argValues)
: Value("argValues", ValueType::FunctionCallArgumentValues)
, argValues(argValues)
{}
const std::vector<ExprEngine::ValuePtr> argValues;
};
class BailoutValue : public Value {
public:
BailoutValue() : Value("bailout", ValueType::BailoutValue) {}
bool isEqual(const DataBase * /*dataBase*/, int /*value*/) const OVERRIDE {
return true;
}
bool isUninit(const DataBase *dataBase) const OVERRIDE {
(void)dataBase;
return true;
}
};
typedef std::function<void (const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback;
/** Execute all functions */
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);
void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings);
void dump(ExprEngine::ValuePtr val);
}
#endif // exprengineH