ExprEngine: Add condition branches for the while loops (#2970)
This commit is contained in:
parent
a9e7974963
commit
259f562e73
|
@ -141,6 +141,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <tuple>
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
#include <z3++.h>
|
#include <z3++.h>
|
||||||
#include <z3_version.h>
|
#include <z3_version.h>
|
||||||
|
@ -1309,12 +1310,12 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ExprEngine::IntRange::isEqual(DataBase *dataBase, int value) const
|
bool ExprEngine::IntRange::isEqual(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (value < minValue || value > maxValue)
|
if (value < minValue || value > maxValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
|
@ -1341,12 +1342,12 @@ bool ExprEngine::IntRange::isEqual(DataBase *dataBase, int value) const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::IntRange::isGreaterThan(DataBase *dataBase, int value) const
|
bool ExprEngine::IntRange::isGreaterThan(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (maxValue <= value)
|
if (maxValue <= value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
|
@ -1373,12 +1374,12 @@ bool ExprEngine::IntRange::isGreaterThan(DataBase *dataBase, int value) const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::IntRange::isLessThan(DataBase *dataBase, int value) const
|
bool ExprEngine::IntRange::isLessThan(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (minValue >= value)
|
if (minValue >= value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
|
@ -1405,13 +1406,13 @@ bool ExprEngine::IntRange::isLessThan(DataBase *dataBase, int value) const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::FloatRange::isEqual(DataBase *dataBase, int value) const
|
bool ExprEngine::FloatRange::isEqual(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (MathLib::isFloat(name)) {
|
if (MathLib::isFloat(name)) {
|
||||||
float f = MathLib::toDoubleNumber(name);
|
float f = MathLib::toDoubleNumber(name);
|
||||||
return value >= f - 0.00001 && value <= f + 0.00001;
|
return value >= f - 0.00001 && value <= f + 0.00001;
|
||||||
}
|
}
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
|
@ -1444,12 +1445,12 @@ bool ExprEngine::FloatRange::isEqual(DataBase *dataBase, int value) const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::FloatRange::isGreaterThan(DataBase *dataBase, int value) const
|
bool ExprEngine::FloatRange::isGreaterThan(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (value < minValue || value > maxValue)
|
if (value < minValue || value > maxValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
if (MathLib::isFloat(name))
|
if (MathLib::isFloat(name))
|
||||||
|
@ -1478,12 +1479,12 @@ bool ExprEngine::FloatRange::isGreaterThan(DataBase *dataBase, int value) const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::FloatRange::isLessThan(DataBase *dataBase, int value) const
|
bool ExprEngine::FloatRange::isLessThan(const DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
if (value < minValue || value > maxValue)
|
if (value < minValue || value > maxValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Data *data = dynamic_cast<Data *>(dataBase);
|
const Data *data = dynamic_cast<const Data *>(dataBase);
|
||||||
if (data->constraints.empty())
|
if (data->constraints.empty())
|
||||||
return true;
|
return true;
|
||||||
if (MathLib::isFloat(name))
|
if (MathLib::isFloat(name))
|
||||||
|
@ -1513,7 +1514,7 @@ bool ExprEngine::FloatRange::isLessThan(DataBase *dataBase, int value) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ExprEngine::BinOpResult::isEqual(ExprEngine::DataBase *dataBase, int value) const
|
bool ExprEngine::BinOpResult::isEqual(const ExprEngine::DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
try {
|
try {
|
||||||
|
@ -1539,7 +1540,7 @@ bool ExprEngine::BinOpResult::isEqual(ExprEngine::DataBase *dataBase, int value)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::BinOpResult::isGreaterThan(ExprEngine::DataBase *dataBase, int value) const
|
bool ExprEngine::BinOpResult::isGreaterThan(const ExprEngine::DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
try {
|
try {
|
||||||
|
@ -1565,7 +1566,7 @@ bool ExprEngine::BinOpResult::isGreaterThan(ExprEngine::DataBase *dataBase, int
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::BinOpResult::isLessThan(ExprEngine::DataBase *dataBase, int value) const
|
bool ExprEngine::BinOpResult::isLessThan(const ExprEngine::DataBase *dataBase, int value) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
try {
|
try {
|
||||||
|
@ -1591,7 +1592,7 @@ bool ExprEngine::BinOpResult::isLessThan(ExprEngine::DataBase *dataBase, int val
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprEngine::BinOpResult::isTrue(ExprEngine::DataBase *dataBase) const
|
bool ExprEngine::BinOpResult::isTrue(const ExprEngine::DataBase *dataBase) const
|
||||||
{
|
{
|
||||||
#ifdef USE_Z3
|
#ifdef USE_Z3
|
||||||
try {
|
try {
|
||||||
|
@ -2460,6 +2461,25 @@ static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data)
|
||||||
|
|
||||||
static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data);
|
static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data);
|
||||||
|
|
||||||
|
static std::tuple<bool, bool> checkConditionBranches(const ExprEngine::ValuePtr &condValue, const Data &data) {
|
||||||
|
bool canBeFalse = true;
|
||||||
|
bool canBeTrue = true;
|
||||||
|
if (auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(condValue)) {
|
||||||
|
canBeFalse = b->isEqual(&data, 0);
|
||||||
|
canBeTrue = b->isTrue(&data);
|
||||||
|
} else if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(condValue)) {
|
||||||
|
canBeFalse = i->isEqual(&data, 0);
|
||||||
|
canBeTrue = ExprEngine::BinOpResult("!=", i, std::make_shared<ExprEngine::IntRange>("0", 0, 0)).isTrue(&data);
|
||||||
|
} else if (std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(condValue)) {
|
||||||
|
canBeFalse = false;
|
||||||
|
canBeTrue = true;
|
||||||
|
} else if (auto f = std::dynamic_pointer_cast<ExprEngine::FloatRange>(condValue)) {
|
||||||
|
canBeFalse = f->isEqual(&data, 0);
|
||||||
|
canBeTrue = ExprEngine::BinOpResult("!=", f, std::make_shared<ExprEngine::FloatRange>("0.0", 0.0, 0.0)).isTrue(&data);
|
||||||
|
}
|
||||||
|
return std::make_tuple(canBeFalse, canBeTrue);
|
||||||
|
}
|
||||||
|
|
||||||
static std::string execute(const Token *start, const Token *end, Data &data)
|
static std::string execute(const Token *start, const Token *end, Data &data)
|
||||||
{
|
{
|
||||||
if (data.recursion > 20)
|
if (data.recursion > 20)
|
||||||
|
@ -2550,21 +2570,8 @@ static std::string execute(const Token *start, const Token *end, Data &data)
|
||||||
const Token *cond = tok->next()->astOperand2(); // TODO: C++17 condition
|
const Token *cond = tok->next()->astOperand2(); // TODO: C++17 condition
|
||||||
const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
|
const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
|
||||||
|
|
||||||
bool canBeFalse = true;
|
bool canBeFalse, canBeTrue;
|
||||||
bool canBeTrue = true;
|
std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data);
|
||||||
if (auto b = std::dynamic_pointer_cast<ExprEngine::BinOpResult>(condValue)) {
|
|
||||||
canBeFalse = b->isEqual(&data, 0);
|
|
||||||
canBeTrue = b->isTrue(&data);
|
|
||||||
} else if (auto i = std::dynamic_pointer_cast<ExprEngine::IntRange>(condValue)) {
|
|
||||||
canBeFalse = i->isEqual(&data, 0);
|
|
||||||
canBeTrue = ExprEngine::BinOpResult("!=", i, std::make_shared<ExprEngine::IntRange>("0", 0, 0)).isTrue(&data);
|
|
||||||
} else if (std::dynamic_pointer_cast<ExprEngine::StringLiteralValue>(condValue)) {
|
|
||||||
canBeFalse = false;
|
|
||||||
canBeTrue = true;
|
|
||||||
} else if (auto f = std::dynamic_pointer_cast<ExprEngine::FloatRange>(condValue)) {
|
|
||||||
canBeFalse = f->isEqual(&data, 0);
|
|
||||||
canBeTrue = ExprEngine::BinOpResult("!=", f, std::make_shared<ExprEngine::FloatRange>("0.0", 0.0, 0.0)).isTrue(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Data &thenData(data);
|
Data &thenData(data);
|
||||||
Data elseData(data);
|
Data elseData(data);
|
||||||
|
@ -2672,109 +2679,149 @@ static std::string execute(const Token *start, const Token *end, Data &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, "for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
|
if (Token::Match(tok, "for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
|
||||||
|
const Token *cond = tok->next()->astOperand2();
|
||||||
|
const ExprEngine::ValuePtr condValue = executeExpression(cond, data);
|
||||||
|
|
||||||
|
bool canBeFalse = false, canBeTrue = true;
|
||||||
|
if (tok->str() == "while")
|
||||||
|
std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data);
|
||||||
|
|
||||||
|
Data &bodyData(data);
|
||||||
|
Data noexecData(data);
|
||||||
|
if (canBeFalse && canBeTrue) { // Avoid that constraints are overspecified
|
||||||
|
bodyData.addConstraint(condValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::ifSplit(tok, bodyData, noexecData);
|
||||||
|
|
||||||
const Token *bodyStart = tok->linkAt(1)->next();
|
const Token *bodyStart = tok->linkAt(1)->next();
|
||||||
const Token *bodyEnd = bodyStart->link();
|
const Token *bodyEnd = bodyStart->link();
|
||||||
|
|
||||||
// TODO this is very rough code
|
// TODO this is very rough code
|
||||||
std::set<int> changedVariables;
|
if (canBeTrue) {
|
||||||
for (const Token *tok2 = tok; tok2 != bodyEnd; tok2 = tok2->next()) {
|
std::set<int> changedVariables;
|
||||||
if (Token::Match(tok2, "%assign%")) {
|
for (const Token *tok2 = tok; tok2 != bodyEnd; tok2 = tok2->next()) {
|
||||||
const Token *lhs = tok2->astOperand1();
|
if (Token::Match(tok2, "%assign%")) {
|
||||||
while (Token::simpleMatch(lhs, "["))
|
const Token *lhs = tok2->astOperand1();
|
||||||
lhs = lhs->astOperand1();
|
while (Token::simpleMatch(lhs, "["))
|
||||||
if (!lhs)
|
lhs = lhs->astOperand1();
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
if (!lhs)
|
||||||
if (Token::Match(lhs, ". %name% =|[") && Token::simpleMatch(lhs->astOperand1(), ".")) {
|
|
||||||
const Token *structToken = lhs;
|
|
||||||
while (Token::Match(structToken, ".|["))
|
|
||||||
structToken = structToken->astOperand1();
|
|
||||||
if (Token::Match(structToken, "%var%")) {
|
|
||||||
data.assignValue(structToken, structToken->varId(), std::make_shared<ExprEngine::BailoutValue>());
|
|
||||||
changedVariables.insert(structToken->varId());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Token::Match(lhs, ". %name% =|[") && lhs->astOperand1() && lhs->astOperand1()->valueType()) {
|
|
||||||
const Token *structToken = lhs->astOperand1();
|
|
||||||
if (!structToken->valueType() || !structToken->varId())
|
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
const Scope *structScope = structToken->valueType()->typeScope;
|
if (Token::Match(lhs, ". %name% =|[") && Token::simpleMatch(lhs->astOperand1(), ".")) {
|
||||||
if (!structScope)
|
const Token *structToken = lhs;
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
while (Token::Match(structToken, ".|["))
|
||||||
const std::string &memberName = tok2->previous()->str();
|
structToken = structToken->astOperand1();
|
||||||
ExprEngine::ValuePtr memberValue;
|
if (Token::Match(structToken, "%var%")) {
|
||||||
for (const Variable &member : structScope->varlist) {
|
bodyData.assignValue(structToken, structToken->varId(), std::make_shared<ExprEngine::BailoutValue>());
|
||||||
if (memberName == member.name() && member.valueType()) {
|
changedVariables.insert(structToken->varId());
|
||||||
memberValue = createVariableValue(member, data);
|
continue;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!memberValue)
|
if (Token::Match(lhs, ". %name% =|[") && lhs->astOperand1() && lhs->astOperand1()->valueType()) {
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
const Token *structToken = lhs->astOperand1();
|
||||||
|
if (!structToken->valueType() || !structToken->varId())
|
||||||
ExprEngine::ValuePtr structVal1 = data.getValue(structToken->varId(), structToken->valueType(), structToken);
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
if (!structVal1)
|
const Scope *structScope = structToken->valueType()->typeScope;
|
||||||
structVal1 = createVariableValue(*structToken->variable(), data);
|
if (!structScope)
|
||||||
auto structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(structVal1);
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
if (!structVal) {
|
const std::string &memberName = tok2->previous()->str();
|
||||||
// Handle pointer to a struct
|
ExprEngine::ValuePtr memberValue;
|
||||||
if (auto structPtr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(structVal1)) {
|
for (const Variable &member : structScope->varlist) {
|
||||||
if (structPtr->pointer && !structPtr->data.empty()) {
|
if (memberName == member.name() && member.valueType()) {
|
||||||
auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
|
memberValue = createVariableValue(member, bodyData);
|
||||||
for (auto val: structPtr->read(indexValue)) {
|
break;
|
||||||
structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(val.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!structVal)
|
if (!memberValue)
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
}
|
|
||||||
|
|
||||||
data.assignStructMember(tok2, &*structVal, memberName, memberValue);
|
ExprEngine::ValuePtr structVal1 = bodyData.getValue(structToken->varId(), structToken->valueType(), structToken);
|
||||||
continue;
|
if (!structVal1)
|
||||||
}
|
structVal1 = createVariableValue(*structToken->variable(), bodyData);
|
||||||
if (lhs->isUnaryOp("*") && lhs->astOperand1()->varId()) {
|
auto structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(structVal1);
|
||||||
const Token *varToken = tok2->astOperand1()->astOperand1();
|
if (!structVal) {
|
||||||
ExprEngine::ValuePtr val = data.getValue(varToken->varId(), varToken->valueType(), varToken);
|
// Handle pointer to a struct
|
||||||
if (val && val->type == ExprEngine::ValueType::ArrayValue) {
|
if (auto structPtr = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(structVal1)) {
|
||||||
// Try to assign "any" value
|
if (structPtr->pointer && !structPtr->data.empty()) {
|
||||||
auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val);
|
auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
|
||||||
arrayValue->assign(std::make_shared<ExprEngine::IntRange>("0", 0, 0), std::make_shared<ExprEngine::BailoutValue>());
|
for (auto val: structPtr->read(indexValue)) {
|
||||||
|
structVal = std::dynamic_pointer_cast<ExprEngine::StructValue>(val.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!structVal)
|
||||||
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyData.assignStructMember(tok2, &*structVal, memberName, memberValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (lhs->isUnaryOp("*") && lhs->astOperand1()->varId()) {
|
||||||
|
const Token *varToken = tok2->astOperand1()->astOperand1();
|
||||||
|
ExprEngine::ValuePtr val = bodyData.getValue(varToken->varId(), varToken->valueType(), varToken);
|
||||||
|
if (val && val->type == ExprEngine::ValueType::ArrayValue) {
|
||||||
|
// Try to assign "any" value
|
||||||
|
auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val);
|
||||||
|
arrayValue->assign(std::make_shared<ExprEngine::IntRange>("0", 0, 0), std::make_shared<ExprEngine::BailoutValue>());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!lhs->variable())
|
||||||
|
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
||||||
|
// give variable "any" value
|
||||||
|
int varid = lhs->varId();
|
||||||
|
if (changedVariables.find(varid) != changedVariables.end())
|
||||||
|
continue;
|
||||||
|
changedVariables.insert(varid);
|
||||||
|
auto oldValue = bodyData.getValue(varid, nullptr, nullptr);
|
||||||
|
if (oldValue && oldValue->isUninit())
|
||||||
|
call(bodyData.callbacks, lhs, oldValue, &bodyData);
|
||||||
|
if (oldValue && oldValue->type == ExprEngine::ValueType::ArrayValue) {
|
||||||
|
// Try to assign "any" value
|
||||||
|
auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(oldValue);
|
||||||
|
arrayValue->assign(std::make_shared<ExprEngine::IntRange>(bodyData.getNewSymbolName(), 0, ~0ULL), std::make_shared<ExprEngine::BailoutValue>());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bodyData.assignValue(tok2, varid, getValueRangeFromValueType(lhs->valueType(), bodyData));
|
||||||
|
continue;
|
||||||
|
} else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
|
||||||
|
// give variable "any" value
|
||||||
|
const Token *vartok = tok2->astOperand1();
|
||||||
|
int varid = vartok->varId();
|
||||||
|
if (changedVariables.find(varid) != changedVariables.end())
|
||||||
|
continue;
|
||||||
|
changedVariables.insert(varid);
|
||||||
|
auto oldValue = bodyData.getValue(varid, nullptr, nullptr);
|
||||||
|
if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue)
|
||||||
|
call(bodyData.callbacks, tok2, oldValue, &bodyData);
|
||||||
|
bodyData.assignValue(tok2, varid, getValueRangeFromValueType(vartok->valueType(), bodyData));
|
||||||
}
|
}
|
||||||
if (!lhs->variable())
|
|
||||||
throw ExprEngineException(tok2, "Unhandled assignment in loop");
|
|
||||||
// give variable "any" value
|
|
||||||
int varid = lhs->varId();
|
|
||||||
if (changedVariables.find(varid) != changedVariables.end())
|
|
||||||
continue;
|
|
||||||
changedVariables.insert(varid);
|
|
||||||
auto oldValue = data.getValue(varid, nullptr, nullptr);
|
|
||||||
if (oldValue && oldValue->isUninit())
|
|
||||||
call(data.callbacks, lhs, oldValue, &data);
|
|
||||||
if (oldValue && oldValue->type == ExprEngine::ValueType::ArrayValue) {
|
|
||||||
// Try to assign "any" value
|
|
||||||
auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(oldValue);
|
|
||||||
arrayValue->assign(std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL), std::make_shared<ExprEngine::BailoutValue>());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
data.assignValue(tok2, varid, getValueRangeFromValueType(lhs->valueType(), data));
|
|
||||||
continue;
|
|
||||||
} else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
|
|
||||||
// give variable "any" value
|
|
||||||
const Token *vartok = tok2->astOperand1();
|
|
||||||
int varid = vartok->varId();
|
|
||||||
if (changedVariables.find(varid) != changedVariables.end())
|
|
||||||
continue;
|
|
||||||
changedVariables.insert(varid);
|
|
||||||
auto oldValue = data.getValue(varid, nullptr, nullptr);
|
|
||||||
if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue)
|
|
||||||
call(data.callbacks, tok2, oldValue, &data);
|
|
||||||
data.assignValue(tok2, varid, getValueRangeFromValueType(vartok->valueType(), data));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tok = tok->linkAt(1);
|
|
||||||
|
const Token *exceptionToken = nullptr;
|
||||||
|
std::string exceptionMessage;
|
||||||
|
auto exec = [&](const Token *tok1, const Token *tok2, Data& data) {
|
||||||
|
try {
|
||||||
|
execute(tok1, tok2, data);
|
||||||
|
} catch (ExprEngineException &e) {
|
||||||
|
if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) {
|
||||||
|
exceptionToken = e.tok;
|
||||||
|
exceptionMessage = e.what;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (canBeTrue)
|
||||||
|
exec(bodyStart->next(), end, bodyData);
|
||||||
|
if (canBeFalse)
|
||||||
|
exec(bodyEnd, end, noexecData);
|
||||||
|
|
||||||
|
if (exceptionToken)
|
||||||
|
throw ExprEngineException(exceptionToken, exceptionMessage);
|
||||||
|
|
||||||
|
return (canBeTrue ? bodyData.str() : std::string()) +
|
||||||
|
(canBeFalse ? noexecData.str() : std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "} else {"))
|
if (Token::simpleMatch(tok, "} else {"))
|
||||||
|
|
|
@ -103,17 +103,17 @@ namespace ExprEngine {
|
||||||
virtual std::string getSymbolicExpression() const {
|
virtual std::string getSymbolicExpression() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
virtual bool isEqual(DataBase *dataBase, int value) const {
|
virtual bool isEqual(const DataBase *dataBase, int value) const {
|
||||||
(void)dataBase;
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual bool isGreaterThan(DataBase *dataBase, int value) const {
|
virtual bool isGreaterThan(const DataBase *dataBase, int value) const {
|
||||||
(void)dataBase;
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual bool isLessThan(DataBase *dataBase, int value) const {
|
virtual bool isLessThan(const DataBase *dataBase, int value) const {
|
||||||
(void)dataBase;
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return false;
|
return false;
|
||||||
|
@ -129,7 +129,7 @@ namespace ExprEngine {
|
||||||
class UninitValue: public Value {
|
class UninitValue: public Value {
|
||||||
public:
|
public:
|
||||||
UninitValue() : Value("?", ValueType::UninitValue) {}
|
UninitValue() : Value("?", ValueType::UninitValue) {}
|
||||||
bool isEqual(DataBase *dataBase, int value) const OVERRIDE {
|
bool isEqual(const DataBase *dataBase, int value) const OVERRIDE {
|
||||||
(void)dataBase;
|
(void)dataBase;
|
||||||
(void)value;
|
(void)value;
|
||||||
return true;
|
return true;
|
||||||
|
@ -152,9 +152,9 @@ namespace ExprEngine {
|
||||||
return str(minValue);
|
return str(minValue);
|
||||||
return str(minValue) + ":" + str(maxValue);
|
return str(minValue) + ":" + str(maxValue);
|
||||||
}
|
}
|
||||||
bool isEqual(DataBase *dataBase, int value) const OVERRIDE;
|
bool isEqual(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isGreaterThan(DataBase *dataBase, int value) const OVERRIDE;
|
bool isGreaterThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isLessThan(DataBase *dataBase, int value) const OVERRIDE;
|
bool isLessThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
|
|
||||||
int128_t minValue;
|
int128_t minValue;
|
||||||
int128_t maxValue;
|
int128_t maxValue;
|
||||||
|
@ -173,9 +173,9 @@ namespace ExprEngine {
|
||||||
return std::to_string(minValue) + ":" + std::to_string(maxValue);
|
return std::to_string(minValue) + ":" + std::to_string(maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEqual(DataBase *dataBase, int value) const OVERRIDE;
|
bool isEqual(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isGreaterThan(DataBase *dataBase, int value) const OVERRIDE;
|
bool isGreaterThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isLessThan(DataBase *dataBase, int value) const OVERRIDE;
|
bool isLessThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
|
|
||||||
long double minValue;
|
long double minValue;
|
||||||
long double maxValue;
|
long double maxValue;
|
||||||
|
@ -283,10 +283,10 @@ namespace ExprEngine {
|
||||||
, op2(op2) {
|
, op2(op2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEqual(DataBase *dataBase, int value) const OVERRIDE;
|
bool isEqual(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isGreaterThan(DataBase *dataBase, int value) const OVERRIDE;
|
bool isGreaterThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
virtual bool isLessThan(DataBase *dataBase, int value) const OVERRIDE;
|
virtual bool isLessThan(const DataBase *dataBase, int value) const OVERRIDE;
|
||||||
bool isTrue(DataBase *dataBase) const;
|
bool isTrue(const DataBase *dataBase) const;
|
||||||
|
|
||||||
std::string getExpr(DataBase *dataBase) const;
|
std::string getExpr(DataBase *dataBase) const;
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ namespace ExprEngine {
|
||||||
class BailoutValue : public Value {
|
class BailoutValue : public Value {
|
||||||
public:
|
public:
|
||||||
BailoutValue() : Value("bailout", ValueType::BailoutValue) {}
|
BailoutValue() : Value("bailout", ValueType::BailoutValue) {}
|
||||||
bool isEqual(DataBase * /*dataBase*/, int /*value*/) const OVERRIDE {
|
bool isEqual(const DataBase * /*dataBase*/, int /*value*/) const OVERRIDE {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool isUninit() const OVERRIDE {
|
bool isUninit() const OVERRIDE {
|
||||||
|
|
|
@ -668,10 +668,14 @@ private:
|
||||||
" x = x + 34;\n"
|
" x = x + 34;\n"
|
||||||
" x == 340;\n"
|
" x == 340;\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS("(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n"
|
const char expected[] = "(< 0 $1)\n"
|
||||||
"(= (+ $2 34) 340)\n"
|
"(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n"
|
||||||
"z3::sat\n",
|
"(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n"
|
||||||
expr(code, "=="));
|
"(= (+ $2 34) 340)\n"
|
||||||
|
"z3::sat\n"
|
||||||
|
"(= 0 340)\n"
|
||||||
|
"z3::unsat\n";
|
||||||
|
ASSERT_EQUALS(expected, expr(code, "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
void while2() {
|
void while2() {
|
||||||
|
@ -681,10 +685,14 @@ private:
|
||||||
" x++;\n"
|
" x++;\n"
|
||||||
" x == 1;\n"
|
" x == 1;\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS("(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n"
|
const char expected[] = "(< 0 $1)\n"
|
||||||
"(= (+ $2 1) 1)\n"
|
"(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n"
|
||||||
"z3::sat\n",
|
"(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n"
|
||||||
expr(code, "=="));
|
"(= (+ $2 1) 1)\n"
|
||||||
|
"z3::sat\n"
|
||||||
|
"(= 0 1)\n"
|
||||||
|
"z3::unsat\n";
|
||||||
|
ASSERT_EQUALS(expected, expr(code, "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
void while3() {
|
void while3() {
|
||||||
|
@ -706,8 +714,14 @@ private:
|
||||||
" *len = 0;\n"
|
" *len = 0;\n"
|
||||||
" *len == 0;\n"
|
" *len == 0;\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS("(= 0 0)\n"
|
const char expected[] = "(distinct |$2:0| 0)\n"
|
||||||
"z3::sat\n", expr(code, "=="));
|
"(and (>= |$2:0| (- 128)) (<= |$2:0| 127))\n"
|
||||||
|
"(= 0 0)\n"
|
||||||
|
"z3::sat\n"
|
||||||
|
"(and (>= $8 (- 2147483648)) (<= $8 2147483647))\n"
|
||||||
|
"(= $8 0)\n"
|
||||||
|
"z3::sat\n";
|
||||||
|
ASSERT_EQUALS(expected, expr(code, "=="));
|
||||||
}
|
}
|
||||||
|
|
||||||
void while5() {
|
void while5() {
|
||||||
|
|
Loading…
Reference in New Issue