ExprEngine: Better handling of if/else
This commit is contained in:
parent
7ab22c7176
commit
d916379f9f
|
@ -121,6 +121,7 @@ namespace {
|
||||||
int * const symbolValueIndex;
|
int * const symbolValueIndex;
|
||||||
const Tokenizer * const tokenizer;
|
const Tokenizer * const tokenizer;
|
||||||
const std::vector<ExprEngine::Callback> &callbacks;
|
const std::vector<ExprEngine::Callback> &callbacks;
|
||||||
|
std::vector<ExprEngine::ValuePtr> conditions;
|
||||||
|
|
||||||
void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) {
|
void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) {
|
||||||
mTrackExecution->symbolRange(tok, value);
|
mTrackExecution->symbolRange(tok, value);
|
||||||
|
@ -142,63 +143,6 @@ namespace {
|
||||||
structVal->member[memberName] = value;
|
structVal->member[memberName] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Data> getData(const Token *cond, bool trueData) {
|
|
||||||
std::vector<Data> ret;
|
|
||||||
ret.push_back(Data(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution));
|
|
||||||
for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) {
|
|
||||||
for (Data &data : ret)
|
|
||||||
data.memory[mem->first] = mem->second;
|
|
||||||
|
|
||||||
if (cond->isComparisonOp() && cond->astOperand1()->varId() == mem->first && cond->astOperand2()->isNumber()) {
|
|
||||||
const int128_t rhsValue = MathLib::toLongNumber(cond->astOperand2()->str());
|
|
||||||
if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) {
|
|
||||||
if (cond->str() == ">") {
|
|
||||||
if (trueData) {
|
|
||||||
if (intRange->maxValue <= rhsValue)
|
|
||||||
return std::vector<Data>();
|
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), rhsValue + 1, intRange->maxValue);
|
|
||||||
ret[0].assignValue(cond, mem->first, val);
|
|
||||||
} else { /* if (!trueData) */
|
|
||||||
if (intRange->maxValue <= rhsValue)
|
|
||||||
return std::vector<Data>();
|
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, rhsValue);
|
|
||||||
ret[0].assignValue(cond, mem->first, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (cond->varId() == mem->first) {
|
|
||||||
if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) {
|
|
||||||
if (trueData) {
|
|
||||||
if (intRange->minValue == 0 && intRange->maxValue == 0)
|
|
||||||
return std::vector<Data>();
|
|
||||||
if (intRange->minValue < 0) {
|
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, -1);
|
|
||||||
ret[0].assignValue(cond, mem->first, val);
|
|
||||||
}
|
|
||||||
if (intRange->maxValue > 0) {
|
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), 1, intRange->maxValue);
|
|
||||||
if (intRange->minValue < 0) {
|
|
||||||
// create additional intrange..
|
|
||||||
ret.push_back(Data(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution));
|
|
||||||
ret.back().memory = ret[0].memory;
|
|
||||||
}
|
|
||||||
ret[0].assignValue(cond, mem->first, val);
|
|
||||||
}
|
|
||||||
} else { /* if (!trueData) */
|
|
||||||
if (intRange->maxValue < 0 || intRange->minValue > 0)
|
|
||||||
return std::vector<Data>();
|
|
||||||
|
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), 0, 0);
|
|
||||||
ret[0].assignValue(cond, mem->first, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getNewSymbolName() override {
|
std::string getNewSymbolName() override {
|
||||||
return "$" + std::to_string(++(*symbolValueIndex));
|
return "$" + std::to_string(++(*symbolValueIndex));
|
||||||
}
|
}
|
||||||
|
@ -249,6 +193,36 @@ namespace {
|
||||||
s << "}";
|
s << "}";
|
||||||
mTrackExecution->state(tok, s.str());
|
mTrackExecution->state(tok, s.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExprEngine::ValuePtr notValue(ExprEngine::ValuePtr v) {
|
||||||
|
auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(v);
|
||||||
|
if (b) {
|
||||||
|
std::string binop;
|
||||||
|
if (b->binop == "==")
|
||||||
|
binop = "!=";
|
||||||
|
else if (b->binop == "!=")
|
||||||
|
binop = "==";
|
||||||
|
else if (b->binop == ">=")
|
||||||
|
binop = "<";
|
||||||
|
else if (b->binop == "<=")
|
||||||
|
binop = ">";
|
||||||
|
else if (b->binop == ">")
|
||||||
|
binop = "<=";
|
||||||
|
else if (b->binop == "<")
|
||||||
|
binop = ">=";
|
||||||
|
if (!binop.empty())
|
||||||
|
return std::make_shared<ExprEngine::BinOpResult>(binop, b->op1, b->op2);
|
||||||
|
}
|
||||||
|
auto zero = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
|
||||||
|
return std::make_shared<ExprEngine::BinOpResult>("==", v, zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCondition(ExprEngine::ValuePtr condValue, bool trueCond) {
|
||||||
|
if (trueCond)
|
||||||
|
conditions.push_back(condValue);
|
||||||
|
else
|
||||||
|
conditions.push_back(notValue(condValue));
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
TrackExecution * const mTrackExecution;
|
TrackExecution * const mTrackExecution;
|
||||||
const int mDataIndex;
|
const int mDataIndex;
|
||||||
|
@ -542,6 +516,20 @@ static z3::expr getExpr(const ExprEngine::BinOpResult *b, ExprData &exprData)
|
||||||
return op1 % op2;
|
return op1 % op2;
|
||||||
if (b->binop == "==")
|
if (b->binop == "==")
|
||||||
return op1 == op2;
|
return op1 == op2;
|
||||||
|
if (b->binop == "!=")
|
||||||
|
return op1 != op2;
|
||||||
|
if (b->binop == ">=")
|
||||||
|
return op1 >= op2;
|
||||||
|
if (b->binop == "<=")
|
||||||
|
return op1 <= op2;
|
||||||
|
if (b->binop == ">")
|
||||||
|
return op1 > op2;
|
||||||
|
if (b->binop == "<")
|
||||||
|
return op1 < op2;
|
||||||
|
if (b->binop == "&&")
|
||||||
|
return op1 && op2;
|
||||||
|
if (b->binop == "||")
|
||||||
|
return op1 || op2;
|
||||||
throw std::runtime_error("Internal error: Unhandled operator");
|
throw std::runtime_error("Internal error: Unhandled operator");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,30 +557,39 @@ static z3::expr getExpr(ExprEngine::ValuePtr v, ExprData &exprData)
|
||||||
throw std::runtime_error("Internal error: Unhandled value type");
|
throw std::runtime_error("Internal error: Unhandled value type");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
bool ExprEngine::BinOpResult::isIntValueInRange(int value) const
|
bool ExprEngine::BinOpResult::isIntValueInRange(ExprEngine::DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
ExprData exprData;
|
ExprData exprData;
|
||||||
z3::solver s(exprData.c);
|
z3::solver solver(exprData.c);
|
||||||
s.add(::getExpr(this, exprData) == value);
|
z3::expr e = ::getExpr(this, exprData);
|
||||||
return s.check() == z3::sat;
|
exprData.addAssertions(solver);
|
||||||
|
for (auto condition : dynamic_cast<const Data *>(dataBase)->conditions)
|
||||||
|
solver.add(::getExpr(condition, exprData));
|
||||||
|
solver.add(e == value);
|
||||||
|
return solver.check() == z3::sat;
|
||||||
#else
|
#else
|
||||||
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExprEngine::BinOpResult::getExpr() const
|
std::string ExprEngine::BinOpResult::getExpr(ExprEngine::DataBase *dataBase) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
ExprData exprData;
|
ExprData exprData;
|
||||||
z3::solver s(exprData.c);
|
z3::solver solver(exprData.c);
|
||||||
s.add(::getExpr(this, exprData));
|
z3::expr e = ::getExpr(this, exprData);
|
||||||
exprData.addAssertions(s);
|
exprData.addAssertions(solver);
|
||||||
|
for (auto condition : dynamic_cast<const Data *>(dataBase)->conditions)
|
||||||
|
solver.add(::getExpr(condition, exprData));
|
||||||
|
solver.add(e);
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << s;
|
os << solver;
|
||||||
return os.str();
|
return os.str();
|
||||||
#else
|
#else
|
||||||
|
(void)dataBase;
|
||||||
return "";
|
return "";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -650,11 +647,11 @@ static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void call(const std::vector<ExprEngine::Callback> &callbacks, const Token *tok, ExprEngine::ValuePtr value)
|
static void call(const std::vector<ExprEngine::Callback> &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase)
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value) {
|
||||||
for (ExprEngine::Callback f : callbacks) {
|
for (ExprEngine::Callback f : callbacks) {
|
||||||
f(tok, *value);
|
f(tok, *value, dataBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -664,7 +661,7 @@ static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data);
|
||||||
static ExprEngine::ValuePtr executeReturn(const Token *tok, Data &data)
|
static ExprEngine::ValuePtr executeReturn(const Token *tok, Data &data)
|
||||||
{
|
{
|
||||||
ExprEngine::ValuePtr retval = executeExpression(tok->astOperand1(), data);
|
ExprEngine::ValuePtr retval = executeExpression(tok->astOperand1(), data);
|
||||||
call(data.callbacks, tok, retval);
|
call(data.callbacks, tok, retval, &data);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,7 +716,7 @@ static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
|
||||||
|
|
||||||
const Token *lhsToken = tok->astOperand1();
|
const Token *lhsToken = tok->astOperand1();
|
||||||
assignValue = truncateValue(assignValue, lhsToken->valueType(), data);
|
assignValue = truncateValue(assignValue, lhsToken->valueType(), data);
|
||||||
call(data.callbacks, tok, assignValue);
|
call(data.callbacks, tok, assignValue, &data);
|
||||||
|
|
||||||
if (lhsToken->varId() > 0) {
|
if (lhsToken->varId() > 0) {
|
||||||
data.assignValue(lhsToken, lhsToken->varId(), assignValue);
|
data.assignValue(lhsToken, lhsToken->varId(), assignValue);
|
||||||
|
@ -792,7 +789,7 @@ static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
|
||||||
throw std::runtime_error("Expression '" + tok->expressionString() + "' has unknown type!");
|
throw std::runtime_error("Expression '" + tok->expressionString() + "' has unknown type!");
|
||||||
|
|
||||||
auto val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
||||||
call(data.callbacks, tok, val);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,7 +800,7 @@ static ExprEngine::ValuePtr executeArrayIndex(const Token *tok, Data &data)
|
||||||
auto indexValue = executeExpression(tok->astOperand2(), data);
|
auto indexValue = executeExpression(tok->astOperand2(), data);
|
||||||
auto conditionalValues = arrayValue->read(indexValue);
|
auto conditionalValues = arrayValue->read(indexValue);
|
||||||
for (auto value: conditionalValues)
|
for (auto value: conditionalValues)
|
||||||
call(data.callbacks, tok, value.second);
|
call(data.callbacks, tok, value.second, &data);
|
||||||
if (conditionalValues.size() == 1 && !conditionalValues[0].first)
|
if (conditionalValues.size() == 1 && !conditionalValues[0].first)
|
||||||
return conditionalValues[0].second;
|
return conditionalValues[0].second;
|
||||||
return std::make_shared<ExprEngine::ConditionalValue>(data.getNewSymbolName(), conditionalValues);
|
return std::make_shared<ExprEngine::ConditionalValue>(data.getNewSymbolName(), conditionalValues);
|
||||||
|
@ -855,16 +852,16 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
|
||||||
if (tok->originalName() == "->") {
|
if (tok->originalName() == "->") {
|
||||||
std::shared_ptr<ExprEngine::PointerValue> pointerValue = std::dynamic_pointer_cast<ExprEngine::PointerValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
std::shared_ptr<ExprEngine::PointerValue> pointerValue = std::dynamic_pointer_cast<ExprEngine::PointerValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
||||||
if (pointerValue) {
|
if (pointerValue) {
|
||||||
call(data.callbacks, tok->astOperand1(), pointerValue);
|
call(data.callbacks, tok->astOperand1(), pointerValue, &data);
|
||||||
structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(pointerValue->data);
|
structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(pointerValue->data);
|
||||||
} else {
|
} else {
|
||||||
call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
|
call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr), &data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!structValue)
|
if (!structValue)
|
||||||
return ExprEngine::ValuePtr();
|
return ExprEngine::ValuePtr();
|
||||||
}
|
}
|
||||||
call(data.callbacks, tok->astOperand1(), structValue);
|
call(data.callbacks, tok->astOperand1(), structValue, &data);
|
||||||
return structValue->getValueOfMember(tok->astOperand2()->str());
|
return structValue->getValueOfMember(tok->astOperand2()->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,7 +871,7 @@ static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data)
|
||||||
ExprEngine::ValuePtr v2 = executeExpression(tok->astOperand2(), data);
|
ExprEngine::ValuePtr v2 = executeExpression(tok->astOperand2(), data);
|
||||||
if (v1 && v2) {
|
if (v1 && v2) {
|
||||||
auto result = simplifyValue(std::make_shared<ExprEngine::BinOpResult>(tok->str(), v1, v2));
|
auto result = simplifyValue(std::make_shared<ExprEngine::BinOpResult>(tok->str(), v1, v2));
|
||||||
call(data.callbacks, tok, result);
|
call(data.callbacks, tok, result, &data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return ExprEngine::ValuePtr();
|
return ExprEngine::ValuePtr();
|
||||||
|
@ -883,7 +880,7 @@ static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data)
|
||||||
static ExprEngine::ValuePtr executeAddressOf(const Token *tok, Data &data)
|
static ExprEngine::ValuePtr executeAddressOf(const Token *tok, Data &data)
|
||||||
{
|
{
|
||||||
auto addr = std::make_shared<ExprEngine::AddressOfValue>(data.getNewSymbolName(), tok->astOperand1()->varId());
|
auto addr = std::make_shared<ExprEngine::AddressOfValue>(data.getNewSymbolName(), tok->astOperand1()->varId());
|
||||||
call(data.callbacks, tok, addr);
|
call(data.callbacks, tok, addr, &data);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,13 +891,13 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
|
||||||
auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
|
auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(pval);
|
||||||
if (addressOf) {
|
if (addressOf) {
|
||||||
auto val = data.getValue(addressOf->varId, tok->valueType(), tok);
|
auto val = data.getValue(addressOf->varId, tok->valueType(), tok);
|
||||||
call(data.callbacks, tok, val);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
auto pointer = std::dynamic_pointer_cast<ExprEngine::PointerValue>(pval);
|
auto pointer = std::dynamic_pointer_cast<ExprEngine::PointerValue>(pval);
|
||||||
if (pointer) {
|
if (pointer) {
|
||||||
auto val = pointer->data;
|
auto val = pointer->data;
|
||||||
call(data.callbacks, tok, val);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -910,14 +907,14 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
|
||||||
static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data)
|
static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data)
|
||||||
{
|
{
|
||||||
auto val = data.getValue(tok->varId(), tok->valueType(), tok);
|
auto val = data.getValue(tok->varId(), tok->valueType(), tok);
|
||||||
call(data.callbacks, tok, val);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data)
|
static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data)
|
||||||
{
|
{
|
||||||
auto val = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), tok->getKnownIntValue(), tok->getKnownIntValue());
|
auto val = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), tok->getKnownIntValue(), tok->getKnownIntValue());
|
||||||
call(data.callbacks, tok, val);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,20 +1024,23 @@ static void execute(const Token *start, const Token *end, Data &data)
|
||||||
|
|
||||||
else if (Token::simpleMatch(tok, "if (")) {
|
else if (Token::simpleMatch(tok, "if (")) {
|
||||||
const Token *cond = tok->next()->astOperand2();
|
const Token *cond = tok->next()->astOperand2();
|
||||||
/*const ExprEngine::ValuePtr condValue =*/ executeExpression(cond,data);
|
const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
|
||||||
std::vector<Data> trueData = data.getData(cond, true);
|
Data ifData(data);
|
||||||
std::vector<Data> falseData = data.getData(cond, false);
|
Data elseData(data);
|
||||||
|
ifData.addCondition(condValue, true);
|
||||||
|
elseData.addCondition(condValue, false);
|
||||||
|
|
||||||
const Token *thenStart = tok->linkAt(1)->next();
|
const Token *thenStart = tok->linkAt(1)->next();
|
||||||
const Token *thenEnd = thenStart->link();
|
const Token *thenEnd = thenStart->link();
|
||||||
for (Data &d : trueData)
|
execute(thenStart->next(), thenEnd, ifData);
|
||||||
execute(thenStart->next(), end, d);
|
|
||||||
if (Token::simpleMatch(thenEnd, "} else {")) {
|
if (Token::simpleMatch(thenEnd, "} else {")) {
|
||||||
const Token *elseStart = thenEnd->tokAt(2);
|
const Token *elseStart = thenEnd->tokAt(2);
|
||||||
for (Data &d : falseData)
|
execute(elseStart->next(), end, elseData);
|
||||||
execute(elseStart->next(), end, d);
|
execute(elseStart->link()->next(), end, ifData);
|
||||||
} else {
|
} else {
|
||||||
for (Data &d : falseData)
|
// TODO: Merge ifData and elseData
|
||||||
execute(thenEnd->next(), end, d);
|
execute(thenEnd->next(), end, ifData);
|
||||||
|
execute(thenEnd->next(), end, elseData);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1156,17 +1156,17 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to
|
||||||
|
|
||||||
void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
|
void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
|
||||||
{
|
{
|
||||||
std::function<void(const Token *, const ExprEngine::Value &)> divByZero = [=](const Token *tok, const ExprEngine::Value &value) {
|
std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> divByZero = [=](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) {
|
||||||
if (!Token::Match(tok->astParent(), "[/%]"))
|
if (!Token::Match(tok->astParent(), "[/%]"))
|
||||||
return;
|
return;
|
||||||
if (tok->astParent()->astOperand2() == tok && value.isIntValueInRange(0)) {
|
if (tok->astParent()->astOperand2() == tok && value.isIntValueInRange(dataBase, 0)) {
|
||||||
std::list<const Token*> callstack{tok->astParent()};
|
std::list<const Token*> callstack{tok->astParent()};
|
||||||
ErrorLogger::ErrorMessage errmsg(callstack, &tokenizer->list, Severity::SeverityType::error, "verificationDivByZero", "There is division, cannot determine that there can't be a division by zero.", CWE(369), false);
|
ErrorLogger::ErrorMessage errmsg(callstack, &tokenizer->list, Severity::SeverityType::error, "verificationDivByZero", "There is division, cannot determine that there can't be a division by zero.", CWE(369), false);
|
||||||
errorLogger->reportErr(errmsg);
|
errorLogger->reportErr(errmsg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::function<void(const Token *, const ExprEngine::Value &)> nullPointerDereference = [=](const Token *tok, const ExprEngine::Value &value) {
|
std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> nullPointerDereference = [=](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) {
|
||||||
if (!tok->astParent())
|
if (!tok->astParent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1183,7 +1183,7 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
|
||||||
if (auto pointerValue = dynamic_cast<const ExprEngine::PointerValue*>(&value)) {
|
if (auto pointerValue = dynamic_cast<const ExprEngine::PointerValue*>(&value)) {
|
||||||
if (!pointerValue->null)
|
if (!pointerValue->null)
|
||||||
return;
|
return;
|
||||||
} else if (!value.isIntValueInRange(0))
|
} else if (!value.isIntValueInRange(dataBase, 0))
|
||||||
return;
|
return;
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
return;
|
return;
|
||||||
|
@ -1195,7 +1195,7 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef VERIFY_INTEGEROVERFLOW
|
#ifdef VERIFY_INTEGEROVERFLOW
|
||||||
std::function<void(const Token *, const ExprEngine::Value &)> integerOverflow = [&](const Token *tok, const ExprEngine::Value &value) {
|
std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> integerOverflow = [&](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) {
|
||||||
if (!tok->isArithmeticalOp() || !tok->valueType() || !tok->valueType()->isIntegral() || tok->valueType()->pointer > 0)
|
if (!tok->isArithmeticalOp() || !tok->valueType() || !tok->valueType()->isIntegral() || tok->valueType()->pointer > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,8 @@ namespace ExprEngine {
|
||||||
virtual std::string getSymbolicExpression() const {
|
virtual std::string getSymbolicExpression() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
virtual bool isIntValueInRange(int value) const {
|
virtual bool isIntValueInRange(DataBase *dataBase, int value) const {
|
||||||
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +113,8 @@ namespace ExprEngine {
|
||||||
return str(minValue);
|
return str(minValue);
|
||||||
return str(minValue) + ":" + str(maxValue);
|
return str(minValue) + ":" + str(maxValue);
|
||||||
}
|
}
|
||||||
bool isIntValueInRange(int value) const override {
|
bool isIntValueInRange(DataBase *dataBase, int value) const override {
|
||||||
|
(void)dataBase;
|
||||||
return value >= minValue && value <= maxValue;
|
return value >= minValue && value <= maxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +234,8 @@ namespace ExprEngine {
|
||||||
, op2(op2) {
|
, op2(op2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isIntValueInRange(int value) const;
|
bool isIntValueInRange(DataBase *dataBase, int value) const;
|
||||||
std::string getExpr() const;
|
std::string getExpr(DataBase *dataBase) const;
|
||||||
|
|
||||||
std::string binop;
|
std::string binop;
|
||||||
ValuePtr op1;
|
ValuePtr op1;
|
||||||
|
@ -262,7 +264,7 @@ namespace ExprEngine {
|
||||||
char sign;
|
char sign;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<void(const Token *, const ExprEngine::Value &)> Callback;
|
typedef std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback;
|
||||||
|
|
||||||
/** Execute all functions */
|
/** Execute all functions */
|
||||||
void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace);
|
void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace);
|
||||||
|
|
|
@ -42,10 +42,6 @@ private:
|
||||||
TEST_CASE(exprAssign2); // Truncation
|
TEST_CASE(exprAssign2); // Truncation
|
||||||
|
|
||||||
TEST_CASE(if1);
|
TEST_CASE(if1);
|
||||||
TEST_CASE(if2);
|
|
||||||
TEST_CASE(if3);
|
|
||||||
TEST_CASE(if4);
|
|
||||||
TEST_CASE(if5);
|
|
||||||
TEST_CASE(ifelse1);
|
TEST_CASE(ifelse1);
|
||||||
|
|
||||||
TEST_CASE(array1);
|
TEST_CASE(array1);
|
||||||
|
@ -83,13 +79,13 @@ private:
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
std::string ret;
|
std::string ret;
|
||||||
std::function<void(const Token *, const ExprEngine::Value &)> f = [&](const Token *tok, const ExprEngine::Value &value) {
|
std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> f = [&](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) {
|
||||||
if (tok->str() != binop)
|
if (tok->str() != binop)
|
||||||
return;
|
return;
|
||||||
auto b = dynamic_cast<const ExprEngine::BinOpResult *>(&value);
|
auto b = dynamic_cast<const ExprEngine::BinOpResult *>(&value);
|
||||||
if (!b)
|
if (!b)
|
||||||
return;
|
return;
|
||||||
ret = b->getExpr();
|
ret = b->getExpr(dataBase);
|
||||||
};
|
};
|
||||||
std::vector<ExprEngine::Callback> callbacks;
|
std::vector<ExprEngine::Callback> callbacks;
|
||||||
callbacks.push_back(f);
|
callbacks.push_back(f);
|
||||||
|
@ -106,7 +102,8 @@ private:
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
std::string ret;
|
std::string ret;
|
||||||
std::function<void(const Token *, const ExprEngine::Value &)> f = [&](const Token *tok, const ExprEngine::Value &value) {
|
std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> f = [&](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) {
|
||||||
|
(void)dataBase;
|
||||||
if ((linenr == 0 || linenr == tok->linenr()) && tok->expressionString() == str) {
|
if ((linenr == 0 || linenr == tok->linenr()) && tok->expressionString() == str) {
|
||||||
if (!ret.empty())
|
if (!ret.empty())
|
||||||
ret += ",";
|
ret += ",";
|
||||||
|
@ -163,27 +160,24 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void if1() {
|
void if1() {
|
||||||
ASSERT_EQUALS("($2)+(1)", getRange("inf f(short x) { if (x > 5) a = x + 1; }", "x+1"));
|
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
||||||
}
|
"(declare-fun v1 () Int)\n"
|
||||||
|
"(assert (<= v0 2147483647))\n"
|
||||||
void if2() {
|
"(assert (>= v0 (- 2147483648)))\n"
|
||||||
ASSERT_EQUALS("($2)+(1),($3)+(1)", getRange("inf f(short x) { if (x > 5) {} a = x + 1; }", "x+1"));
|
"(assert (<= v1 2147483647))\n"
|
||||||
}
|
"(assert (>= v1 (- 2147483648)))\n"
|
||||||
|
"(assert (< v0 v1))\n"
|
||||||
void if3() {
|
"(assert (= v0 v1))\n",
|
||||||
ASSERT_EQUALS("1,-2147483648:2147483647,-2147483648:2147483647", getRange("void f() { int x; if (a) { if (b) x=1; } x=x; }", "x=x"));
|
expr("void f(int x, int y) { if (x < y) return x == y; }", "=="));
|
||||||
}
|
|
||||||
|
|
||||||
void if4() {
|
|
||||||
ASSERT_EQUALS("1:2147483647,-2147483648:-1", getRange("int x; void f() { if (x) { a=x; }}", "a=x"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void if5() {
|
|
||||||
ASSERT_EQUALS("0", getRange("int x; void f() { if (x) {} else { a=x; }}", "a=x"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ifelse1() {
|
void ifelse1() {
|
||||||
ASSERT_EQUALS("($3)+(1)", getRange("inf f(short x) { if (x > 5) ; else a = x + 1; }", "x+1"));
|
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
||||||
|
"(assert (<= v0 32767))\n"
|
||||||
|
"(assert (>= v0 (- 32768)))\n"
|
||||||
|
"(assert (<= v0 5))\n"
|
||||||
|
"(assert (= (+ v0 2) 40))\n",
|
||||||
|
expr("void f(short x) { if (x > 5) ; else if (x+2==40); }", "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -194,9 +188,9 @@ private:
|
||||||
|
|
||||||
void array2() {
|
void array2() {
|
||||||
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
||||||
"(assert (= v0 365))\n"
|
|
||||||
"(assert (<= v0 255))\n"
|
"(assert (<= v0 255))\n"
|
||||||
"(assert (>= v0 0))\n",
|
"(assert (>= v0 0))\n"
|
||||||
|
"(assert (= v0 365))\n",
|
||||||
expr("void dostuff(unsigned char *); int f() { unsigned char arr[10] = \"\"; dostuff(arr); return arr[4] == 365; }", "=="));
|
expr("void dostuff(unsigned char *); int f() { unsigned char arr[10] = \"\"; dostuff(arr); return arr[4] == 365; }", "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,9 +253,9 @@ private:
|
||||||
|
|
||||||
void int1() {
|
void int1() {
|
||||||
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
||||||
"(assert (= (+ 2 v0) 3))\n"
|
|
||||||
"(assert (<= v0 2147483647))\n"
|
"(assert (<= v0 2147483647))\n"
|
||||||
"(assert (>= v0 (- 2147483648)))\n",
|
"(assert (>= v0 (- 2147483648)))\n"
|
||||||
|
"(assert (= (+ 2 v0) 3))\n",
|
||||||
expr("void f(int x) { return 2+x==3; }", "=="));
|
expr("void f(int x) { return 2+x==3; }", "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,13 +293,13 @@ private:
|
||||||
|
|
||||||
|
|
||||||
void structMember() {
|
void structMember() {
|
||||||
ASSERT_EQUALS("(declare-fun v1 () Int)\n"
|
ASSERT_EQUALS("(declare-fun v0 () Int)\n"
|
||||||
"(declare-fun v0 () Int)\n"
|
"(declare-fun v1 () Int)\n"
|
||||||
"(assert (= (+ v0 v1) 0))\n"
|
|
||||||
"(assert (<= v0 255))\n"
|
"(assert (<= v0 255))\n"
|
||||||
"(assert (>= v0 0))\n"
|
"(assert (>= v0 0))\n"
|
||||||
"(assert (<= v1 255))\n"
|
"(assert (<= v1 255))\n"
|
||||||
"(assert (>= v1 0))\n",
|
"(assert (>= v1 0))\n"
|
||||||
|
"(assert (= (+ v0 v1) 0))\n",
|
||||||
expr("struct S {\n"
|
expr("struct S {\n"
|
||||||
" unsigned char a;\n"
|
" unsigned char a;\n"
|
||||||
" unsigned char b;\n"
|
" unsigned char b;\n"
|
||||||
|
|
Loading…
Reference in New Issue