Verification; Merged handling of pointers and arrays

This commit is contained in:
Daniel Marjamäki 2019-12-29 16:26:11 +01:00
parent 1cef732e1b
commit 2710a94b4b
3 changed files with 59 additions and 51 deletions

View File

@ -360,8 +360,9 @@ static int128_t truncateInt(int128_t value, int bits, char sign)
return value; return value;
} }
ExprEngine::ArrayValue::ArrayValue(const std::string &name, ExprEngine::ValuePtr size, ExprEngine::ValuePtr value) ExprEngine::ArrayValue::ArrayValue(const std::string &name, ExprEngine::ValuePtr size, ExprEngine::ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer)
: Value(name, ExprEngine::ValueType::ArrayValue) : Value(name, ExprEngine::ValueType::ArrayValue)
, pointer(pointer), nullPointer(nullPointer), uninitPointer(uninitPointer)
, size(size) , size(size)
{ {
assign(ExprEngine::ValuePtr(), value); assign(ExprEngine::ValuePtr(), value);
@ -369,6 +370,7 @@ ExprEngine::ArrayValue::ArrayValue(const std::string &name, ExprEngine::ValuePtr
ExprEngine::ArrayValue::ArrayValue(DataBase *data, const Variable *var) ExprEngine::ArrayValue::ArrayValue(DataBase *data, const Variable *var)
: Value(data->getNewSymbolName(), ExprEngine::ValueType::ArrayValue) : Value(data->getNewSymbolName(), ExprEngine::ValueType::ArrayValue)
, pointer(var->isPointer()), nullPointer(var->isPointer()), uninitPointer(var->isPointer())
{ {
if (var) { if (var) {
int sz = 1; int sz = 1;
@ -393,6 +395,16 @@ ExprEngine::ArrayValue::ArrayValue(DataBase *data, const Variable *var)
assign(ExprEngine::ValuePtr(), val); assign(ExprEngine::ValuePtr(), val);
} }
std::string ExprEngine::ArrayValue::getRange() const
{
std::string r = getSymbolicExpression();
if (nullPointer)
r += std::string(r.empty() ? "" : ",") + "null";
if (uninitPointer)
r += std::string(r.empty() ? "" : ",") + "->?";
return r;
}
void ExprEngine::ArrayValue::assign(ExprEngine::ValuePtr index, ExprEngine::ValuePtr value) void ExprEngine::ArrayValue::assign(ExprEngine::ValuePtr index, ExprEngine::ValuePtr value)
{ {
if (!index) if (!index)
@ -541,18 +553,6 @@ std::string ExprEngine::StructValue::getSymbolicExpression() const
return ostr.str(); return ostr.str();
} }
std::string ExprEngine::PointerValue::getRange() const
{
std::string r;
if (data)
r = "->" + data->getSymbolicExpression();
if (null)
r += std::string(r.empty() ? "" : ",") + "null";
if (uninitData)
r += std::string(r.empty() ? "" : ",") + "->?";
return r;
}
std::string ExprEngine::IntegerTruncation::getSymbolicExpression() const std::string ExprEngine::IntegerTruncation::getSymbolicExpression() const
{ {
return sign + std::to_string(bits) + "(" + inputValue->getSymbolicExpression() + ")"; return sign + std::to_string(bits) + "(" + inputValue->getSymbolicExpression() + ")";
@ -983,7 +983,7 @@ static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
if (!rhsValue && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->container && tok->astOperand2()->valueType()->container->stdStringLike) { if (!rhsValue && tok->astOperand2()->valueType() && tok->astOperand2()->valueType()->container && tok->astOperand2()->valueType()->container->stdStringLike) {
auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL); auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL);
auto value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127); auto value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
rhsValue = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, value); rhsValue = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, value, false, false, false);
call(data.callbacks, tok->astOperand2(), rhsValue, &data); call(data.callbacks, tok->astOperand2(), rhsValue, &data);
} }
@ -1114,13 +1114,14 @@ static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
if (tok->valueType()->pointer == 0) if (tok->valueType()->pointer == 0)
return range; return range;
bool uninit = false, null = false; bool uninitPointer = false, nullPointer = false;
if (val && val->type == ExprEngine::ValueType::PointerValue) { if (val && val->type == ExprEngine::ValueType::ArrayValue) {
null = std::static_pointer_cast<ExprEngine::PointerValue>(val)->null; nullPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->nullPointer;
uninit = std::static_pointer_cast<ExprEngine::PointerValue>(val)->uninitData; uninitPointer = std::static_pointer_cast<ExprEngine::ArrayValue>(val)->uninitPointer;
} }
return std::make_shared<ExprEngine::PointerValue>(data.getNewSymbolName(), range, null, uninit); auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ~0UL);
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, range, true, nullPointer, uninitPointer);
} }
if (val) if (val)
@ -1140,10 +1141,10 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr)); std::shared_ptr<ExprEngine::StructValue> structValue = std::dynamic_pointer_cast<ExprEngine::StructValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
if (!structValue) { if (!structValue) {
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::ArrayValue> pointerValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr));
if (pointerValue) { if (pointerValue && pointerValue->pointer && pointerValue->data.size() == 1) {
call(data.callbacks, tok->astOperand1(), pointerValue, &data); 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[0].value);
} else { } else {
call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr), &data); call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr), &data);
} }
@ -1190,7 +1191,7 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
if (!pval) { if (!pval) {
auto v = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings); auto v = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
if (tok->astOperand1()->varId()) { if (tok->astOperand1()->varId()) {
pval = std::make_shared<ExprEngine::PointerValue>(data.getNewSymbolName(), v, false, false); pval = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), ExprEngine::ValuePtr(), v, true, false, false);
data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval); data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval);
} }
call(data.callbacks, tok, v, &data); call(data.callbacks, tok, v, &data);
@ -1202,11 +1203,15 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
call(data.callbacks, tok, val, &data); 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::ArrayValue>(pval);
if (pointer) { if (pointer) {
auto val = pointer->data; auto indexValue = std::make_shared<ExprEngine::IntRange>("0", 0, 0);
call(data.callbacks, tok, val, &data); auto conditionalValues = pointer->read(indexValue);
return val; for (auto value: conditionalValues)
call(data.callbacks, tok, value.second, &data);
if (conditionalValues.size() == 1 && !conditionalValues[0].first)
return conditionalValues[0].second;
return std::make_shared<ExprEngine::ConditionalValue>(data.getNewSymbolName(), conditionalValues);
} }
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
} }
@ -1522,7 +1527,8 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
ValueType vt(*valueType); ValueType vt(*valueType);
vt.pointer = 0; vt.pointer = 0;
auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings); auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
return std::make_shared<ExprEngine::PointerValue>(data.getNewSymbolName(), range, true, true); auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ~0UL);
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, range, true, true, true);
} }
if (var.isArray()) if (var.isArray())
return std::make_shared<ExprEngine::ArrayValue>(&data, &var); return std::make_shared<ExprEngine::ArrayValue>(&data, &var);
@ -1535,7 +1541,8 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
return createStructVal(valueType->typeScope, var.isLocal() && !var.isStatic(), data); return createStructVal(valueType->typeScope, var.isLocal() && !var.isStatic(), data);
if (valueType->smartPointerType) { if (valueType->smartPointerType) {
auto structValue = createStructVal(valueType->smartPointerType->classScope, var.isLocal() && !var.isStatic(), data); auto structValue = createStructVal(valueType->smartPointerType->classScope, var.isLocal() && !var.isStatic(), data);
return std::make_shared<ExprEngine::PointerValue>(data.getNewSymbolName(), structValue, true, false); auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ~0UL);
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, structValue, true, true, false);
} }
if (valueType->container) { if (valueType->container) {
ExprEngine::ValuePtr value; ExprEngine::ValuePtr value;
@ -1546,8 +1553,8 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
value = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings); value = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
} else } else
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL); auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0U);
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, value); return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, value, false, false, false);
} }
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
} }

View File

@ -57,7 +57,6 @@ namespace ExprEngine {
UninitValue, UninitValue,
IntRange, IntRange,
FloatRange, FloatRange,
PointerValue,
ConditionalValue, ConditionalValue,
ArrayValue, ArrayValue,
StringLiteralValue, StringLiteralValue,
@ -157,20 +156,6 @@ namespace ExprEngine {
long double maxValue; long double maxValue;
}; };
class PointerValue: public Value {
public:
PointerValue(const std::string &name, ValuePtr data, bool null, bool uninitData)
: Value(name, ValueType::PointerValue)
, data(data)
, null(null)
, uninitData(uninitData) {
}
std::string getRange() const OVERRIDE;
ValuePtr data;
bool null;
bool uninitData;
};
class ConditionalValue : public Value { class ConditionalValue : public Value {
public: public:
typedef std::vector<std::pair<ValuePtr,ValuePtr>> Vector; typedef std::vector<std::pair<ValuePtr,ValuePtr>> Vector;
@ -182,19 +167,25 @@ namespace ExprEngine {
Vector values; Vector values;
}; };
// Array or pointer
class ArrayValue: public Value { class ArrayValue: public Value {
public: public:
const int MAXSIZE = 0x100000; const int MAXSIZE = 0x100000;
ArrayValue(const std::string &name, ValuePtr size, ValuePtr value); ArrayValue(const std::string &name, ValuePtr size, ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer);
ArrayValue(DataBase *data, const Variable *var); ArrayValue(DataBase *data, const Variable *var);
std::string getRange() const;
std::string getSymbolicExpression() const OVERRIDE; std::string getSymbolicExpression() const OVERRIDE;
void assign(ValuePtr index, ValuePtr value); void assign(ValuePtr index, ValuePtr value);
void clear(); void clear();
ConditionalValue::Vector read(ValuePtr index) const; ConditionalValue::Vector read(ValuePtr index) const;
bool pointer;
bool nullPointer;
bool uninitPointer;
struct IndexAndValue { struct IndexAndValue {
ValuePtr index; ValuePtr index;
ValuePtr value; ValuePtr value;

View File

@ -74,6 +74,7 @@ private:
TEST_CASE(int1); TEST_CASE(int1);
TEST_CASE(pointer1); TEST_CASE(pointer1);
TEST_CASE(pointer2);
TEST_CASE(pointerAlias1); TEST_CASE(pointerAlias1);
TEST_CASE(pointerAlias2); TEST_CASE(pointerAlias2);
TEST_CASE(pointerAlias3); TEST_CASE(pointerAlias3);
@ -414,10 +415,19 @@ private:
void pointer1() { void pointer1() {
const char code[] = "void f(unsigned char *p) { return *p == 7; }"; const char code[] = "void f(unsigned char *p) { return *p == 7; }";
ASSERT_EQUALS("->$1,null,->?", getRange(code, "p")); ASSERT_EQUALS("size=$2,[:]=$1,null,->?", getRange(code, "p"));
ASSERT_EQUALS("(declare-fun $1 () Int)\n" ASSERT_EQUALS("(declare-fun |$1:0| () Int)\n"
"(assert (and (>= $1 0) (<= $1 255)))\n" "(assert (and (>= |$1:0| 0) (<= |$1:0| 255)))\n"
"(assert (= $1 7))\n" "(assert (= |$1:0| 7))\n"
"z3::sat",
expr(code, "=="));
}
void pointer2() {
const char code[] = "void f(unsigned char *p) { return p[2] == 7; }";
ASSERT_EQUALS("(declare-fun |$1:2| () Int)\n"
"(assert (and (>= |$1:2| 0) (<= |$1:2| 255)))\n"
"(assert (= |$1:2| 7))\n"
"z3::sat", "z3::sat",
expr(code, "==")); expr(code, "=="));
} }