349 lines
11 KiB
C++
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 ¤tFunction, 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
|