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. | ||||
|  * SMTChecker: Support array ``length``. | ||||
|  * SMTChecker: Support array ``push`` and ``pop``. | ||||
|  * SMTChecker: General support to BitVectors and the bitwise ``and`` operator. | ||||
|  * Add support for natspec comments on state variables. | ||||
| 
 | ||||
| 
 | ||||
| Bugfixes: | ||||
|  * Optimizer: Fixed a bug in BlockDeDuplicator. | ||||
|  * Type Checker: Disallow assignments to storage variables of type ``mapping``. | ||||
|  | ||||
| @ -19,6 +19,8 @@ | ||||
| 
 | ||||
| #include <libsolutil/CommonIO.h> | ||||
| 
 | ||||
| #include <cvc4/util/bitvector.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| 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]); | ||||
| 		else if (n == "mod") | ||||
| 			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") | ||||
| 			return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]); | ||||
| 		else if (n == "store") | ||||
|  | ||||
| @ -126,7 +126,7 @@ pair<CheckResult, vector<string>> SMTLib2Interface::check(vector<Expression> con | ||||
| 		result = CheckResult::ERROR; | ||||
| 
 | ||||
| 	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()); | ||||
| 	return make_pair(result, values); | ||||
| } | ||||
| @ -137,7 +137,40 @@ string SMTLib2Interface::toSExpr(Expression const& _expr) | ||||
| 		return _expr.name; | ||||
| 
 | ||||
| 	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, ""); | ||||
| 		auto sortSort = std::dynamic_pointer_cast<SortSort>(_expr.arguments.at(0).sort); | ||||
|  | ||||
| @ -94,6 +94,9 @@ public: | ||||
| 			{"*", 2}, | ||||
| 			{"/", 2}, | ||||
| 			{"mod", 2}, | ||||
| 			{"bvand", 2}, | ||||
| 			{"int2bv", 2}, | ||||
| 			{"bv2int", 1}, | ||||
| 			{"select", 2}, | ||||
| 			{"store", 3}, | ||||
| 			{"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) | ||||
| 	{ | ||||
| 		return Expression("not", std::move(_a), Kind::Bool); | ||||
| @ -251,6 +280,11 @@ public: | ||||
| 	{ | ||||
| 		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 | ||||
| 	{ | ||||
| 		smtAssert( | ||||
|  | ||||
| @ -24,6 +24,14 @@ namespace solidity::smtutil | ||||
| { | ||||
| 
 | ||||
| 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, | ||||
| 	Bool, | ||||
| 	BitVector, | ||||
| 	Function, | ||||
| 	Array, | ||||
| 	Sort, | ||||
| @ -48,6 +49,36 @@ struct 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 | ||||
| { | ||||
| 	FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain): | ||||
| @ -160,7 +191,9 @@ struct TupleSort: public Sort | ||||
| struct SortProvider | ||||
| { | ||||
| 	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]; | ||||
| 		else if (n == "mod") | ||||
| 			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") | ||||
| 			return z3::select(arguments[0], arguments[1]); | ||||
| 		else if (n == "store") | ||||
|  | ||||
| @ -701,7 +701,7 @@ vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract | ||||
| smtutil::SortPointer CHC::constructorSort() | ||||
| { | ||||
| 	return make_shared<smtutil::FunctionSort>( | ||||
| 		vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts, | ||||
| 		vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts, | ||||
| 		smtutil::SortProvider::boolSort | ||||
| 	); | ||||
| } | ||||
| @ -747,7 +747,7 @@ smtutil::SortPointer CHC::sort(FunctionDefinition const& _function) | ||||
| 	auto inputSorts = applyMap(_function.parameters(), smtSort); | ||||
| 	auto outputSorts = applyMap(_function.returnParameters(), smtSort); | ||||
| 	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 | ||||
| 	); | ||||
| } | ||||
| @ -776,7 +776,7 @@ smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, Contr | ||||
| 	auto inputSorts = applyMap(_function.parameters(), smtSort); | ||||
| 	auto outputSorts = applyMap(_function.returnParameters(), smtSort); | ||||
| 	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 | ||||
| 	); | ||||
| } | ||||
|  | ||||
| @ -574,6 +574,8 @@ void SMTEncoder::endVisit(BinaryOperation const& _op) | ||||
| 		arithmeticOperation(_op); | ||||
| 	else if (TokenTraits::isCompareOp(_op.getOperator())) | ||||
| 		compareOperation(_op); | ||||
| 	else if (TokenTraits::isBitOp(_op.getOperator())) | ||||
| 		bitwiseOperation(_op); | ||||
| 	else | ||||
| 		m_errorReporter.warning( | ||||
| 			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) | ||||
| { | ||||
| 	// Signed division in SMTLIB2 rounds differently for negative division.
 | ||||
|  | ||||
| @ -108,6 +108,7 @@ protected: | ||||
| 	); | ||||
| 	void compareOperation(BinaryOperation const& _op); | ||||
| 	void booleanOperation(BinaryOperation const& _op); | ||||
| 	void bitwiseOperation(BinaryOperation const& _op); | ||||
| 
 | ||||
| 	void initContract(ContractDefinition const& _contract); | ||||
| 	void initFunction(FunctionDefinition const& _function); | ||||
|  | ||||
| @ -63,7 +63,7 @@ private: | ||||
| 
 | ||||
| 	/// Symbolic 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", | ||||
| 		m_context | ||||
| 	}; | ||||
|  | ||||
| @ -34,7 +34,11 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 	switch (smtKind(_type.category())) | ||||
| 	{ | ||||
| 	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: | ||||
| 		return SortProvider::boolSort; | ||||
| 	case Kind::Function: | ||||
| @ -50,7 +54,7 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 			returnSort = SortProvider::boolSort; | ||||
| 		else if (returnTypes.size() > 1) | ||||
| 			// Abstract sort.
 | ||||
| 			returnSort = SortProvider::intSort; | ||||
| 			returnSort = SortProvider::uintSort; | ||||
| 		else | ||||
| 			returnSort = smtSort(*returnTypes.front()); | ||||
| 		return make_shared<FunctionSort>(parameterSorts, returnSort); | ||||
| @ -68,7 +72,7 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 		{ | ||||
| 			auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type); | ||||
| 			solAssert(stringLitType, ""); | ||||
| 			array = make_shared<ArraySort>(SortProvider::intSort, SortProvider::intSort); | ||||
| 			array = make_shared<ArraySort>(SortProvider::uintSort, SortProvider::uintSort); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @ -81,7 +85,7 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 				solAssert(false, ""); | ||||
| 
 | ||||
| 			solAssert(arrayType, ""); | ||||
| 			array = make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType())); | ||||
| 			array = make_shared<ArraySort>(SortProvider::uintSort, smtSortAbstractFunction(*arrayType->baseType())); | ||||
| 		} | ||||
| 
 | ||||
| 		string tupleName; | ||||
| @ -98,7 +102,7 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 		return make_shared<TupleSort>( | ||||
| 			tupleName, | ||||
| 			vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"}, | ||||
| 			vector<SortPointer>{array, SortProvider::intSort} | ||||
| 			vector<SortPointer>{array, SortProvider::uintSort} | ||||
| 		); | ||||
| 	} | ||||
| 	case Kind::Tuple: | ||||
| @ -118,7 +122,7 @@ SortPointer smtSort(frontend::Type const& _type) | ||||
| 	} | ||||
| 	default: | ||||
| 		// 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) | ||||
| { | ||||
| 	if (isFunction(_type.category())) | ||||
| 		return SortProvider::intSort; | ||||
| 		return SortProvider::uintSort; | ||||
| 	return smtSort(_type); | ||||
| } | ||||
| 
 | ||||
| @ -144,7 +148,7 @@ vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const& | ||||
| 		if (type) | ||||
| 			sorts.push_back(smtSortAbstractFunction(*type)); | ||||
| 		else | ||||
| 			sorts.push_back(SortProvider::intSort); | ||||
| 			sorts.push_back(SortProvider::uintSort); | ||||
| 	return sorts; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -286,7 +286,7 @@ SymbolicArrayVariable::SymbolicArrayVariable( | ||||
| 		std::make_shared<TupleSort>( | ||||
| 			"array_length_pair", | ||||
| 			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_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