mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Support to bitwise
This commit is contained in:
parent
9f407fe0e7
commit
9e9f0c52e1
@ -9,8 +9,10 @@ Compiler Features:
|
|||||||
* Build system: Update the soljson.js build to emscripten 1.39.15 and boost 1.73.0 and include Z3 for integrated SMTChecker support without the callback mechanism.
|
* Build system: Update the soljson.js build to emscripten 1.39.15 and boost 1.73.0 and include Z3 for integrated SMTChecker support without the callback mechanism.
|
||||||
* SMTChecker: Support array ``length``.
|
* SMTChecker: Support array ``length``.
|
||||||
* SMTChecker: Support array ``push`` and ``pop``.
|
* SMTChecker: Support array ``push`` and ``pop``.
|
||||||
|
* SMTChecker: General support to BitVectors and the bitwise ``and`` operator.
|
||||||
* Add support for natspec comments on state variables.
|
* Add support for natspec comments on state variables.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
||||||
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <libsolutil/CommonIO.h>
|
#include <libsolutil/CommonIO.h>
|
||||||
|
|
||||||
|
#include <cvc4/util/bitvector.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -185,6 +187,49 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
|
|||||||
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
|
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
|
||||||
else if (n == "mod")
|
else if (n == "mod")
|
||||||
return m_context.mkExpr(CVC4::kind::INTS_MODULUS, arguments[0], arguments[1]);
|
return m_context.mkExpr(CVC4::kind::INTS_MODULUS, arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvand")
|
||||||
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_AND, arguments[0], arguments[1]);
|
||||||
|
else if (n == "int2bv")
|
||||||
|
{
|
||||||
|
size_t size = std::stoi(_expr.arguments[1].name);
|
||||||
|
auto i2bvOp = m_context.mkConst(CVC4::IntToBitVector(size));
|
||||||
|
// CVC4 treats all BVs as unsigned, so we need to manually apply 2's complement if needed.
|
||||||
|
return m_context.mkExpr(
|
||||||
|
CVC4::kind::ITE,
|
||||||
|
m_context.mkExpr(CVC4::kind::GEQ, arguments[0], m_context.mkConst(CVC4::Rational(0))),
|
||||||
|
m_context.mkExpr(CVC4::kind::INT_TO_BITVECTOR, i2bvOp, arguments[0]),
|
||||||
|
m_context.mkExpr(
|
||||||
|
CVC4::kind::BITVECTOR_NEG,
|
||||||
|
m_context.mkExpr(CVC4::kind::INT_TO_BITVECTOR, i2bvOp, m_context.mkExpr(CVC4::kind::UMINUS, arguments[0]))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (n == "bv2int")
|
||||||
|
{
|
||||||
|
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
|
||||||
|
smtAssert(intSort, "");
|
||||||
|
auto nat = m_context.mkExpr(CVC4::kind::BITVECTOR_TO_NAT, arguments[0]);
|
||||||
|
if (!intSort->isSigned)
|
||||||
|
return nat;
|
||||||
|
|
||||||
|
auto type = arguments[0].getType();
|
||||||
|
smtAssert(type.isBitVector(), "");
|
||||||
|
auto size = CVC4::BitVectorType(type).getSize();
|
||||||
|
// CVC4 treats all BVs as unsigned, so we need to manually apply 2's complement if needed.
|
||||||
|
auto extractOp = m_context.mkConst(CVC4::BitVectorExtract(size - 1, size - 1));
|
||||||
|
return m_context.mkExpr(CVC4::kind::ITE,
|
||||||
|
m_context.mkExpr(
|
||||||
|
CVC4::kind::EQUAL,
|
||||||
|
m_context.mkExpr(CVC4::kind::BITVECTOR_EXTRACT, extractOp, arguments[0]),
|
||||||
|
m_context.mkConst(CVC4::BitVector(1, size_t(0)))
|
||||||
|
),
|
||||||
|
nat,
|
||||||
|
m_context.mkExpr(
|
||||||
|
CVC4::kind::UMINUS,
|
||||||
|
m_context.mkExpr(CVC4::kind::BITVECTOR_TO_NAT, m_context.mkExpr(CVC4::kind::BITVECTOR_NEG, arguments[0]))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
else if (n == "select")
|
else if (n == "select")
|
||||||
return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]);
|
return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]);
|
||||||
else if (n == "store")
|
else if (n == "store")
|
||||||
|
@ -126,7 +126,7 @@ pair<CheckResult, vector<string>> SMTLib2Interface::check(vector<Expression> con
|
|||||||
result = CheckResult::ERROR;
|
result = CheckResult::ERROR;
|
||||||
|
|
||||||
vector<string> values;
|
vector<string> values;
|
||||||
if (result == CheckResult::SATISFIABLE && result != CheckResult::ERROR)
|
if (result == CheckResult::SATISFIABLE && !_expressionsToEvaluate.empty())
|
||||||
values = parseValues(find(response.cbegin(), response.cend(), '\n'), response.cend());
|
values = parseValues(find(response.cbegin(), response.cend(), '\n'), response.cend());
|
||||||
return make_pair(result, values);
|
return make_pair(result, values);
|
||||||
}
|
}
|
||||||
@ -137,7 +137,40 @@ string SMTLib2Interface::toSExpr(Expression const& _expr)
|
|||||||
return _expr.name;
|
return _expr.name;
|
||||||
|
|
||||||
std::string sexpr = "(";
|
std::string sexpr = "(";
|
||||||
if (_expr.name == "const_array")
|
if (_expr.name == "int2bv")
|
||||||
|
{
|
||||||
|
size_t size = std::stoi(_expr.arguments[1].name);
|
||||||
|
auto arg = toSExpr(_expr.arguments.front());
|
||||||
|
auto int2bv = "(_ int2bv " + to_string(size) + ")";
|
||||||
|
// Some solvers treat all BVs as unsigned, so we need to manually apply 2's complement if needed.
|
||||||
|
sexpr += string("ite ") +
|
||||||
|
"(>= " + arg + " 0) " +
|
||||||
|
"(" + int2bv + " " + arg + ") " +
|
||||||
|
"(bvneg (" + int2bv + " (- " + arg + ")))";
|
||||||
|
}
|
||||||
|
else if (_expr.name == "bv2int")
|
||||||
|
{
|
||||||
|
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
|
||||||
|
smtAssert(intSort, "");
|
||||||
|
|
||||||
|
auto arg = toSExpr(_expr.arguments.front());
|
||||||
|
auto nat = "(bv2nat " + arg + ")";
|
||||||
|
|
||||||
|
if (!intSort->isSigned)
|
||||||
|
return nat;
|
||||||
|
|
||||||
|
auto bvSort = dynamic_pointer_cast<BitVectorSort>(_expr.arguments.front().sort);
|
||||||
|
smtAssert(bvSort, "");
|
||||||
|
auto size = to_string(bvSort->size);
|
||||||
|
auto pos = to_string(bvSort->size - 1);
|
||||||
|
|
||||||
|
// Some solvers treat all BVs as unsigned, so we need to manually apply 2's complement if needed.
|
||||||
|
sexpr += string("ite ") +
|
||||||
|
"(= ((_ extract " + pos + " " + pos + ")" + arg + ") #b0) " +
|
||||||
|
nat + " " +
|
||||||
|
"(- (bvneg " + arg + "))";
|
||||||
|
}
|
||||||
|
else if (_expr.name == "const_array")
|
||||||
{
|
{
|
||||||
smtAssert(_expr.arguments.size() == 2, "");
|
smtAssert(_expr.arguments.size() == 2, "");
|
||||||
auto sortSort = std::dynamic_pointer_cast<SortSort>(_expr.arguments.at(0).sort);
|
auto sortSort = std::dynamic_pointer_cast<SortSort>(_expr.arguments.at(0).sort);
|
||||||
|
@ -94,6 +94,9 @@ public:
|
|||||||
{"*", 2},
|
{"*", 2},
|
||||||
{"/", 2},
|
{"/", 2},
|
||||||
{"mod", 2},
|
{"mod", 2},
|
||||||
|
{"bvand", 2},
|
||||||
|
{"int2bv", 2},
|
||||||
|
{"bv2int", 1},
|
||||||
{"select", 2},
|
{"select", 2},
|
||||||
{"store", 3},
|
{"store", 3},
|
||||||
{"const_array", 2},
|
{"const_array", 2},
|
||||||
@ -195,6 +198,32 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Expression int2bv(Expression _n, size_t _size)
|
||||||
|
{
|
||||||
|
smtAssert(_n.sort->kind == Kind::Int, "");
|
||||||
|
std::shared_ptr<IntSort> intSort = std::dynamic_pointer_cast<IntSort>(_n.sort);
|
||||||
|
smtAssert(intSort, "");
|
||||||
|
smtAssert(_size <= 256, "");
|
||||||
|
return Expression(
|
||||||
|
"int2bv",
|
||||||
|
std::vector<Expression>{std::move(_n), Expression(_size)},
|
||||||
|
std::make_shared<BitVectorSort>(_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Expression bv2int(Expression _bv, bool _signed = false)
|
||||||
|
{
|
||||||
|
smtAssert(_bv.sort->kind == Kind::BitVector, "");
|
||||||
|
std::shared_ptr<BitVectorSort> bvSort = std::dynamic_pointer_cast<BitVectorSort>(_bv.sort);
|
||||||
|
smtAssert(bvSort, "");
|
||||||
|
smtAssert(bvSort->size <= 256, "");
|
||||||
|
return Expression(
|
||||||
|
"bv2int",
|
||||||
|
std::vector<Expression>{std::move(_bv)},
|
||||||
|
SortProvider::intSort(_signed)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
friend Expression operator!(Expression _a)
|
friend Expression operator!(Expression _a)
|
||||||
{
|
{
|
||||||
return Expression("not", std::move(_a), Kind::Bool);
|
return Expression("not", std::move(_a), Kind::Bool);
|
||||||
@ -251,6 +280,11 @@ public:
|
|||||||
{
|
{
|
||||||
return Expression("mod", std::move(_a), std::move(_b), Kind::Int);
|
return Expression("mod", std::move(_a), std::move(_b), Kind::Int);
|
||||||
}
|
}
|
||||||
|
friend Expression operator&(Expression _a, Expression _b)
|
||||||
|
{
|
||||||
|
auto bvSort = _a.sort;
|
||||||
|
return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
|
}
|
||||||
Expression operator()(std::vector<Expression> _arguments) const
|
Expression operator()(std::vector<Expression> _arguments) const
|
||||||
{
|
{
|
||||||
smtAssert(
|
smtAssert(
|
||||||
|
@ -24,6 +24,14 @@ namespace solidity::smtutil
|
|||||||
{
|
{
|
||||||
|
|
||||||
shared_ptr<Sort> const SortProvider::boolSort{make_shared<Sort>(Kind::Bool)};
|
shared_ptr<Sort> const SortProvider::boolSort{make_shared<Sort>(Kind::Bool)};
|
||||||
shared_ptr<Sort> const SortProvider::intSort{make_shared<Sort>(Kind::Int)};
|
shared_ptr<IntSort> const SortProvider::uintSort{make_shared<IntSort>(false)};
|
||||||
|
shared_ptr<IntSort> const SortProvider::sintSort{make_shared<IntSort>(true)};
|
||||||
|
|
||||||
|
shared_ptr<IntSort> SortProvider::intSort(bool _signed)
|
||||||
|
{
|
||||||
|
if (_signed)
|
||||||
|
return sintSort;
|
||||||
|
return uintSort;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ enum class Kind
|
|||||||
{
|
{
|
||||||
Int,
|
Int,
|
||||||
Bool,
|
Bool,
|
||||||
|
BitVector,
|
||||||
Function,
|
Function,
|
||||||
Array,
|
Array,
|
||||||
Sort,
|
Sort,
|
||||||
@ -48,6 +49,36 @@ struct Sort
|
|||||||
};
|
};
|
||||||
using SortPointer = std::shared_ptr<Sort>;
|
using SortPointer = std::shared_ptr<Sort>;
|
||||||
|
|
||||||
|
struct IntSort: public Sort
|
||||||
|
{
|
||||||
|
IntSort(bool _signed):
|
||||||
|
Sort(Kind::Int),
|
||||||
|
isSigned(_signed)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(IntSort const& _other) const
|
||||||
|
{
|
||||||
|
return Sort::operator==(_other) && isSigned == _other.isSigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSigned;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitVectorSort: public Sort
|
||||||
|
{
|
||||||
|
BitVectorSort(unsigned _size):
|
||||||
|
Sort(Kind::BitVector),
|
||||||
|
size(_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(BitVectorSort const& _other) const
|
||||||
|
{
|
||||||
|
return Sort::operator==(_other) && size == _other.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size;
|
||||||
|
};
|
||||||
|
|
||||||
struct FunctionSort: public Sort
|
struct FunctionSort: public Sort
|
||||||
{
|
{
|
||||||
FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain):
|
FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain):
|
||||||
@ -160,7 +191,9 @@ struct TupleSort: public Sort
|
|||||||
struct SortProvider
|
struct SortProvider
|
||||||
{
|
{
|
||||||
static std::shared_ptr<Sort> const boolSort;
|
static std::shared_ptr<Sort> const boolSort;
|
||||||
static std::shared_ptr<Sort> const intSort;
|
static std::shared_ptr<IntSort> const uintSort;
|
||||||
|
static std::shared_ptr<IntSort> const sintSort;
|
||||||
|
static std::shared_ptr<IntSort> intSort(bool _signed = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,19 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
|||||||
return arguments[0] / arguments[1];
|
return arguments[0] / arguments[1];
|
||||||
else if (n == "mod")
|
else if (n == "mod")
|
||||||
return z3::mod(arguments[0], arguments[1]);
|
return z3::mod(arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvand")
|
||||||
|
return arguments[0] & arguments[1];
|
||||||
|
else if (n == "int2bv")
|
||||||
|
{
|
||||||
|
size_t size = std::stoi(_expr.arguments[1].name);
|
||||||
|
return z3::int2bv(size, arguments[0]);
|
||||||
|
}
|
||||||
|
else if (n == "bv2int")
|
||||||
|
{
|
||||||
|
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
|
||||||
|
smtAssert(intSort, "");
|
||||||
|
return z3::bv2int(arguments[0], intSort->isSigned);
|
||||||
|
}
|
||||||
else if (n == "select")
|
else if (n == "select")
|
||||||
return z3::select(arguments[0], arguments[1]);
|
return z3::select(arguments[0], arguments[1]);
|
||||||
else if (n == "store")
|
else if (n == "store")
|
||||||
|
@ -701,7 +701,7 @@ vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract
|
|||||||
smtutil::SortPointer CHC::constructorSort()
|
smtutil::SortPointer CHC::constructorSort()
|
||||||
{
|
{
|
||||||
return make_shared<smtutil::FunctionSort>(
|
return make_shared<smtutil::FunctionSort>(
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts,
|
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts,
|
||||||
smtutil::SortProvider::boolSort
|
smtutil::SortProvider::boolSort
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -747,7 +747,7 @@ smtutil::SortPointer CHC::sort(FunctionDefinition const& _function)
|
|||||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||||
return make_shared<smtutil::FunctionSort>(
|
return make_shared<smtutil::FunctionSort>(
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
|
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
|
||||||
smtutil::SortProvider::boolSort
|
smtutil::SortProvider::boolSort
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -776,7 +776,7 @@ smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, Contr
|
|||||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||||
return make_shared<smtutil::FunctionSort>(
|
return make_shared<smtutil::FunctionSort>(
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + sorts + inputSorts + sorts + outputSorts,
|
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + sorts + inputSorts + sorts + outputSorts,
|
||||||
smtutil::SortProvider::boolSort
|
smtutil::SortProvider::boolSort
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -574,6 +574,8 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
|
|||||||
arithmeticOperation(_op);
|
arithmeticOperation(_op);
|
||||||
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
||||||
compareOperation(_op);
|
compareOperation(_op);
|
||||||
|
else if (TokenTraits::isBitOp(_op.getOperator()))
|
||||||
|
bitwiseOperation(_op);
|
||||||
else
|
else
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
3876_error,
|
3876_error,
|
||||||
@ -1346,6 +1348,43 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
|
||||||
|
{
|
||||||
|
solAssert(TokenTraits::isBitOp(_op.getOperator()), "");
|
||||||
|
auto commonType = _op.annotation().commonType;
|
||||||
|
solAssert(commonType, "");
|
||||||
|
|
||||||
|
unsigned bvSize = 256;
|
||||||
|
bool isSigned = false;
|
||||||
|
if (auto const* intType = dynamic_cast<IntegerType const*>(commonType))
|
||||||
|
{
|
||||||
|
bvSize = intType->numBits();
|
||||||
|
isSigned = intType->isSigned();
|
||||||
|
}
|
||||||
|
else if (auto const* fixedType = dynamic_cast<FixedPointType const*>(commonType))
|
||||||
|
{
|
||||||
|
bvSize = fixedType->numBits();
|
||||||
|
isSigned = fixedType->isSigned();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression()), bvSize);
|
||||||
|
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression()), bvSize);
|
||||||
|
|
||||||
|
optional<smtutil::Expression> result;
|
||||||
|
if (_op.getOperator() == Token::BitAnd)
|
||||||
|
result = bvLeft & bvRight;
|
||||||
|
// TODO implement the other operators
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
1093_error,
|
||||||
|
_op.location(),
|
||||||
|
"Assertion checker does not yet implement this bitwise operator."
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
|
||||||
|
}
|
||||||
|
|
||||||
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
|
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
|
||||||
{
|
{
|
||||||
// Signed division in SMTLIB2 rounds differently for negative division.
|
// Signed division in SMTLIB2 rounds differently for negative division.
|
||||||
|
@ -108,6 +108,7 @@ protected:
|
|||||||
);
|
);
|
||||||
void compareOperation(BinaryOperation const& _op);
|
void compareOperation(BinaryOperation const& _op);
|
||||||
void booleanOperation(BinaryOperation const& _op);
|
void booleanOperation(BinaryOperation const& _op);
|
||||||
|
void bitwiseOperation(BinaryOperation const& _op);
|
||||||
|
|
||||||
void initContract(ContractDefinition const& _contract);
|
void initContract(ContractDefinition const& _contract);
|
||||||
void initFunction(FunctionDefinition const& _function);
|
void initFunction(FunctionDefinition const& _function);
|
||||||
|
@ -63,7 +63,7 @@ private:
|
|||||||
|
|
||||||
/// Symbolic balances.
|
/// Symbolic balances.
|
||||||
SymbolicArrayVariable m_balances{
|
SymbolicArrayVariable m_balances{
|
||||||
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::intSort, smtutil::SortProvider::intSort),
|
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort),
|
||||||
"balances",
|
"balances",
|
||||||
m_context
|
m_context
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,11 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
switch (smtKind(_type.category()))
|
switch (smtKind(_type.category()))
|
||||||
{
|
{
|
||||||
case Kind::Int:
|
case Kind::Int:
|
||||||
return SortProvider::intSort;
|
if (auto const* intType = dynamic_cast<IntegerType const*>(&_type))
|
||||||
|
return SortProvider::intSort(intType->isSigned());
|
||||||
|
if (auto const* fixedType = dynamic_cast<FixedPointType const*>(&_type))
|
||||||
|
return SortProvider::intSort(fixedType->isSigned());
|
||||||
|
return SortProvider::uintSort;
|
||||||
case Kind::Bool:
|
case Kind::Bool:
|
||||||
return SortProvider::boolSort;
|
return SortProvider::boolSort;
|
||||||
case Kind::Function:
|
case Kind::Function:
|
||||||
@ -50,7 +54,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
returnSort = SortProvider::boolSort;
|
returnSort = SortProvider::boolSort;
|
||||||
else if (returnTypes.size() > 1)
|
else if (returnTypes.size() > 1)
|
||||||
// Abstract sort.
|
// Abstract sort.
|
||||||
returnSort = SortProvider::intSort;
|
returnSort = SortProvider::uintSort;
|
||||||
else
|
else
|
||||||
returnSort = smtSort(*returnTypes.front());
|
returnSort = smtSort(*returnTypes.front());
|
||||||
return make_shared<FunctionSort>(parameterSorts, returnSort);
|
return make_shared<FunctionSort>(parameterSorts, returnSort);
|
||||||
@ -68,7 +72,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
{
|
{
|
||||||
auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type);
|
auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type);
|
||||||
solAssert(stringLitType, "");
|
solAssert(stringLitType, "");
|
||||||
array = make_shared<ArraySort>(SortProvider::intSort, SortProvider::intSort);
|
array = make_shared<ArraySort>(SortProvider::uintSort, SortProvider::uintSort);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -81,7 +85,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
|
|
||||||
solAssert(arrayType, "");
|
solAssert(arrayType, "");
|
||||||
array = make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
|
array = make_shared<ArraySort>(SortProvider::uintSort, smtSortAbstractFunction(*arrayType->baseType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
string tupleName;
|
string tupleName;
|
||||||
@ -98,7 +102,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
return make_shared<TupleSort>(
|
return make_shared<TupleSort>(
|
||||||
tupleName,
|
tupleName,
|
||||||
vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"},
|
vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"},
|
||||||
vector<SortPointer>{array, SortProvider::intSort}
|
vector<SortPointer>{array, SortProvider::uintSort}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case Kind::Tuple:
|
case Kind::Tuple:
|
||||||
@ -118,7 +122,7 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Abstract case.
|
// Abstract case.
|
||||||
return SortProvider::intSort;
|
return SortProvider::uintSort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +137,7 @@ vector<SortPointer> smtSort(vector<frontend::TypePointer> const& _types)
|
|||||||
SortPointer smtSortAbstractFunction(frontend::Type const& _type)
|
SortPointer smtSortAbstractFunction(frontend::Type const& _type)
|
||||||
{
|
{
|
||||||
if (isFunction(_type.category()))
|
if (isFunction(_type.category()))
|
||||||
return SortProvider::intSort;
|
return SortProvider::uintSort;
|
||||||
return smtSort(_type);
|
return smtSort(_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +148,7 @@ vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const&
|
|||||||
if (type)
|
if (type)
|
||||||
sorts.push_back(smtSortAbstractFunction(*type));
|
sorts.push_back(smtSortAbstractFunction(*type));
|
||||||
else
|
else
|
||||||
sorts.push_back(SortProvider::intSort);
|
sorts.push_back(SortProvider::uintSort);
|
||||||
return sorts;
|
return sorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ SymbolicArrayVariable::SymbolicArrayVariable(
|
|||||||
std::make_shared<TupleSort>(
|
std::make_shared<TupleSort>(
|
||||||
"array_length_pair",
|
"array_length_pair",
|
||||||
std::vector<std::string>{"array", "length"},
|
std::vector<std::string>{"array", "length"},
|
||||||
std::vector<SortPointer>{m_sort, SortProvider::intSort}
|
std::vector<SortPointer>{m_sort, SortProvider::uintSort}
|
||||||
),
|
),
|
||||||
m_uniqueName + "_array_length_pair",
|
m_uniqueName + "_array_length_pair",
|
||||||
m_context
|
m_context
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
int8 x = 1;
|
||||||
|
int8 y = 0;
|
||||||
|
assert(x & y != 0);
|
||||||
|
x = -1; y = 3;
|
||||||
|
assert(x & y == 3);
|
||||||
|
y = -1;
|
||||||
|
int8 z = x & y;
|
||||||
|
assert(z == -1);
|
||||||
|
y = 127;
|
||||||
|
assert(x & y == 127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (104-122): Assertion violation happens here
|
@ -0,0 +1,12 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
assert(1 & 0 != 0);
|
||||||
|
assert(-1 & 3 == 3);
|
||||||
|
assert(-1 & -1 == -1);
|
||||||
|
assert(-1 & 127 == 127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (76-94): Assertion violation happens here
|
@ -0,0 +1,18 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
uint8 x = 1;
|
||||||
|
uint16 y = 0;
|
||||||
|
assert(x & y != 0);
|
||||||
|
x = 0xff;
|
||||||
|
y = 0xffff;
|
||||||
|
assert(x & y == 0xff);
|
||||||
|
assert(x & y == 0xffff);
|
||||||
|
assert(x & y == 0x0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (107-125): Assertion violation happens here
|
||||||
|
// Warning: (180-203): Assertion violation happens here
|
||||||
|
// Warning: (207-230): Assertion violation happens here
|
Loading…
Reference in New Issue
Block a user