mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Integration with CVC4
This commit is contained in:
parent
842fd0cd2c
commit
ae3350ae03
@ -1,12 +1,11 @@
|
||||
### 0.4.23 (unreleased)
|
||||
|
||||
Features:
|
||||
|
||||
* SMTChecker: Integration with CVC4 SMT solver
|
||||
|
||||
Bugfixes:
|
||||
|
||||
|
||||
|
||||
### 0.4.22 (2018-04-16)
|
||||
|
||||
Features:
|
||||
@ -34,7 +33,6 @@ Features:
|
||||
* Syntax Tests: Add source locations to syntax test expectations.
|
||||
* Type Checker: Improve documentation and warnings for accessing contract members inherited from ``address``.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Code Generator: Allow ``block.blockhash`` without being called.
|
||||
* Code Generator: Do not include internal functions in the runtime bytecode which are only referenced in the constructor.
|
||||
|
4
cmake/FindCVC4.cmake
Normal file
4
cmake/FindCVC4.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
find_path(CVC4_INCLUDE_DIR cvc4/cvc4.h)
|
||||
find_library(CVC4_LIBRARY NAMES cvc4 )
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CVC4 DEFAULT_MSG CVC4_LIBRARY CVC4_INCLUDE_DIR)
|
3
cmake/FindGMP.cmake
Normal file
3
cmake/FindGMP.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
find_library(GMP_LIBRARY NAMES gmp )
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARY)
|
@ -6,10 +6,25 @@ find_package(Z3 QUIET)
|
||||
if (${Z3_FOUND})
|
||||
include_directories(${Z3_INCLUDE_DIR})
|
||||
add_definitions(-DHAVE_Z3)
|
||||
message("Z3 SMT solver found. This enables optional SMT checking.")
|
||||
message("Z3 SMT solver found. This enables optional SMT checking with Z3.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
else()
|
||||
message("Z3 SMT solver NOT found. Optional SMT checking will not be available. Please install Z3 if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
|
||||
find_package(GMP QUIET)
|
||||
find_package(CVC4 QUIET)
|
||||
if (${CVC4_FOUND})
|
||||
if (${GMP_FOUND})
|
||||
include_directories(${CVC4_INCLUDE_DIR})
|
||||
add_definitions(-DHAVE_CVC4)
|
||||
message("CVC4 SMT solver and GMP found. This enables optional SMT checking with CVC4.")
|
||||
else()
|
||||
message("CVC4 SMT solver found but its dependency GMP was NOT found. Optional SMT checking with CVC4 will not be available. Please install GMP if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
endif()
|
||||
else()
|
||||
message("No SMT solver found (Z3 or CVC4). Optional SMT checking will not be available. Please install Z3 or CVC4 if it is desired.")
|
||||
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(solidity ${sources} ${headers})
|
||||
@ -17,4 +32,9 @@ target_link_libraries(solidity PUBLIC evmasm devcore)
|
||||
|
||||
if (${Z3_FOUND})
|
||||
target_link_libraries(solidity PUBLIC ${Z3_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (${CVC4_FOUND} AND ${GMP_FOUND})
|
||||
target_link_libraries(solidity PUBLIC ${CVC4_LIBRARY})
|
||||
target_link_libraries(solidity PUBLIC ${GMP_LIBRARY})
|
||||
endif()
|
||||
|
200
libsolidity/formal/CVC4Interface.cpp
Normal file
200
libsolidity/formal/CVC4Interface.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolidity/formal/CVC4Interface.h>
|
||||
|
||||
#include <libsolidity/interface/Exceptions.h>
|
||||
|
||||
#include <libdevcore/CommonIO.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::solidity::smt;
|
||||
|
||||
CVC4Interface::CVC4Interface():
|
||||
m_solver(&m_context)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void CVC4Interface::reset()
|
||||
{
|
||||
m_constants.clear();
|
||||
m_functions.clear();
|
||||
m_solver.reset();
|
||||
m_solver.setOption("produce-models", true);
|
||||
}
|
||||
|
||||
void CVC4Interface::push()
|
||||
{
|
||||
m_solver.push();
|
||||
}
|
||||
|
||||
void CVC4Interface::pop()
|
||||
{
|
||||
m_solver.pop();
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newFunction(string _name, Sort _domain, Sort _codomain)
|
||||
{
|
||||
CVC4::Type fType = m_context.mkFunctionType(cvc4Sort(_domain), cvc4Sort(_codomain));
|
||||
m_functions.insert({_name, m_context.mkVar(_name.c_str(), fType)});
|
||||
return SolverInterface::newFunction(move(_name), _domain, _codomain);
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newInteger(string _name)
|
||||
{
|
||||
m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.integerType())});
|
||||
return SolverInterface::newInteger(move(_name));
|
||||
}
|
||||
|
||||
Expression CVC4Interface::newBool(string _name)
|
||||
{
|
||||
m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.booleanType())});
|
||||
return SolverInterface::newBool(std::move(_name));
|
||||
}
|
||||
|
||||
void CVC4Interface::addAssertion(Expression const& _expr)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_solver.assertFormula(toCVC4Expr(_expr));
|
||||
}
|
||||
catch (CVC4::TypeCheckingException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
catch (CVC4::LogicException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
catch (CVC4::UnsafeInterruptException const&)
|
||||
{
|
||||
solAssert(false, "");
|
||||
}
|
||||
}
|
||||
|
||||
pair<CheckResult, vector<string>> CVC4Interface::check(vector<Expression> const& _expressionsToEvaluate)
|
||||
{
|
||||
CheckResult result;
|
||||
vector<string> values;
|
||||
try
|
||||
{
|
||||
switch (m_solver.checkSat().isSat())
|
||||
{
|
||||
case CVC4::Result::SAT:
|
||||
result = CheckResult::SATISFIABLE;
|
||||
break;
|
||||
case CVC4::Result::UNSAT:
|
||||
result = CheckResult::UNSATISFIABLE;
|
||||
break;
|
||||
case CVC4::Result::SAT_UNKNOWN:
|
||||
result = CheckResult::UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "");
|
||||
}
|
||||
|
||||
if (result != CheckResult::UNSATISFIABLE && !_expressionsToEvaluate.empty())
|
||||
{
|
||||
for (Expression const& e: _expressionsToEvaluate)
|
||||
values.push_back(toString(m_solver.getValue(toCVC4Expr(e))));
|
||||
}
|
||||
}
|
||||
catch (CVC4::Exception & e)
|
||||
{
|
||||
result = CheckResult::ERROR;
|
||||
values.clear();
|
||||
}
|
||||
|
||||
return make_pair(result, values);
|
||||
}
|
||||
|
||||
CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
|
||||
{
|
||||
if (_expr.arguments.empty() && m_constants.count(_expr.name))
|
||||
return m_constants.at(_expr.name);
|
||||
vector<CVC4::Expr> arguments;
|
||||
for (auto const& arg: _expr.arguments)
|
||||
arguments.push_back(toCVC4Expr(arg));
|
||||
|
||||
string const& n = _expr.name;
|
||||
if (m_functions.count(n))
|
||||
return m_context.mkExpr(CVC4::kind::APPLY_UF, m_functions[n], arguments);
|
||||
else if (m_constants.count(n))
|
||||
{
|
||||
solAssert(arguments.empty(), "");
|
||||
return m_constants.at(n);
|
||||
}
|
||||
else if (arguments.empty())
|
||||
{
|
||||
if (n == "true")
|
||||
return m_context.mkConst(true);
|
||||
else if (n == "false")
|
||||
return m_context.mkConst(false);
|
||||
else
|
||||
// We assume it is an integer...
|
||||
return m_context.mkConst(CVC4::Rational(n));
|
||||
}
|
||||
|
||||
solAssert(_expr.hasCorrectArity(), "");
|
||||
if (n == "ite")
|
||||
return arguments[0].iteExpr(arguments[1], arguments[2]);
|
||||
else if (n == "not")
|
||||
return arguments[0].notExpr();
|
||||
else if (n == "and")
|
||||
return arguments[0].andExpr(arguments[1]);
|
||||
else if (n == "or")
|
||||
return arguments[0].orExpr(arguments[1]);
|
||||
else if (n == "=")
|
||||
return m_context.mkExpr(CVC4::kind::EQUAL, arguments[0], arguments[1]);
|
||||
else if (n == "<")
|
||||
return m_context.mkExpr(CVC4::kind::LT, arguments[0], arguments[1]);
|
||||
else if (n == "<=")
|
||||
return m_context.mkExpr(CVC4::kind::LEQ, arguments[0], arguments[1]);
|
||||
else if (n == ">")
|
||||
return m_context.mkExpr(CVC4::kind::GT, arguments[0], arguments[1]);
|
||||
else if (n == ">=")
|
||||
return m_context.mkExpr(CVC4::kind::GEQ, arguments[0], arguments[1]);
|
||||
else if (n == "+")
|
||||
return m_context.mkExpr(CVC4::kind::PLUS, arguments[0], arguments[1]);
|
||||
else if (n == "-")
|
||||
return m_context.mkExpr(CVC4::kind::MINUS, arguments[0], arguments[1]);
|
||||
else if (n == "*")
|
||||
return m_context.mkExpr(CVC4::kind::MULT, arguments[0], arguments[1]);
|
||||
else if (n == "/")
|
||||
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
|
||||
// Cannot reach here.
|
||||
solAssert(false, "");
|
||||
return arguments[0];
|
||||
}
|
||||
|
||||
CVC4::Type CVC4Interface::cvc4Sort(Sort _sort)
|
||||
{
|
||||
switch (_sort)
|
||||
{
|
||||
case Sort::Bool:
|
||||
return m_context.booleanType();
|
||||
case Sort::Int:
|
||||
return m_context.integerType();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
solAssert(false, "");
|
||||
// Cannot be reached.
|
||||
return m_context.integerType();
|
||||
}
|
62
libsolidity/formal/CVC4Interface.h
Normal file
62
libsolidity/formal/CVC4Interface.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/formal/SolverInterface.h>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <cvc4/cvc4.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
namespace smt
|
||||
{
|
||||
|
||||
class CVC4Interface: public SolverInterface, public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CVC4Interface();
|
||||
|
||||
void reset() override;
|
||||
|
||||
void push() override;
|
||||
void pop() override;
|
||||
|
||||
Expression newFunction(std::string _name, Sort _domain, Sort _codomain) override;
|
||||
Expression newInteger(std::string _name) override;
|
||||
Expression newBool(std::string _name) override;
|
||||
|
||||
void addAssertion(Expression const& _expr) override;
|
||||
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
||||
|
||||
private:
|
||||
CVC4::Expr toCVC4Expr(Expression const& _expr);
|
||||
CVC4::Type cvc4Sort(smt::Sort _sort);
|
||||
|
||||
CVC4::ExprManager m_context;
|
||||
CVC4::SmtEngine m_solver;
|
||||
std::map<std::string, CVC4::Expr> m_constants;
|
||||
std::map<std::string, CVC4::Expr> m_functions;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
|
||||
#ifdef HAVE_Z3
|
||||
#include <libsolidity/formal/Z3Interface.h>
|
||||
#elif HAVE_CVC4
|
||||
#include <libsolidity/formal/CVC4Interface.h>
|
||||
#else
|
||||
#include <libsolidity/formal/SMTLib2Interface.h>
|
||||
#endif
|
||||
@ -39,6 +41,8 @@ using namespace dev::solidity;
|
||||
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback):
|
||||
#ifdef HAVE_Z3
|
||||
m_interface(make_shared<smt::Z3Interface>()),
|
||||
#elif HAVE_CVC4
|
||||
m_interface(make_shared<smt::CVC4Interface>()),
|
||||
#else
|
||||
m_interface(make_shared<smt::SMTLib2Interface>(_readFileCallback)),
|
||||
#endif
|
||||
|
@ -65,6 +65,26 @@ public:
|
||||
Expression& operator=(Expression const&) = default;
|
||||
Expression& operator=(Expression&&) = default;
|
||||
|
||||
bool hasCorrectArity() const
|
||||
{
|
||||
static std::map<std::string, unsigned> const operatorsArity{
|
||||
{"ite", 3},
|
||||
{"not", 1},
|
||||
{"and", 2},
|
||||
{"or", 2},
|
||||
{"=", 2},
|
||||
{"<", 2},
|
||||
{"<=", 2},
|
||||
{">", 2},
|
||||
{">=", 2},
|
||||
{"+", 2},
|
||||
{"-", 2},
|
||||
{"*", 2},
|
||||
{"/", 2}
|
||||
};
|
||||
return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
|
||||
}
|
||||
|
||||
static Expression ite(Expression _condition, Expression _trueValue, Expression _falseValue)
|
||||
{
|
||||
solAssert(_trueValue.sort == _falseValue.sort, "");
|
||||
|
@ -116,21 +116,6 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
||||
for (auto const& arg: _expr.arguments)
|
||||
arguments.push_back(toZ3Expr(arg));
|
||||
|
||||
static map<string, unsigned> arity{
|
||||
{"ite", 3},
|
||||
{"not", 1},
|
||||
{"and", 2},
|
||||
{"or", 2},
|
||||
{"=", 2},
|
||||
{"<", 2},
|
||||
{"<=", 2},
|
||||
{">", 2},
|
||||
{">=", 2},
|
||||
{"+", 2},
|
||||
{"-", 2},
|
||||
{"*", 2},
|
||||
{"/", 2}
|
||||
};
|
||||
string const& n = _expr.name;
|
||||
if (m_functions.count(n))
|
||||
return m_functions.at(n)(arguments);
|
||||
@ -150,7 +135,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
||||
return m_context.int_val(n.c_str());
|
||||
}
|
||||
|
||||
solAssert(arity.count(n) && arity.at(n) == arguments.size(), "");
|
||||
solAssert(_expr.hasCorrectArity(), "");
|
||||
if (n == "ite")
|
||||
return z3::ite(arguments[0], arguments[1], arguments[2]);
|
||||
else if (n == "not")
|
||||
|
@ -51,9 +51,6 @@ private:
|
||||
z3::expr toZ3Expr(Expression const& _expr);
|
||||
z3::sort z3Sort(smt::Sort _sort);
|
||||
|
||||
std::string checkSatAndGetValuesCommand(std::vector<Expression> const& _expressionsToEvaluate);
|
||||
std::vector<std::string> parseValues(std::string::const_iterator _start, std::string::const_iterator _end);
|
||||
|
||||
z3::context m_context;
|
||||
z3::solver m_solver;
|
||||
std::map<std::string, z3::expr> m_constants;
|
||||
|
Loading…
Reference in New Issue
Block a user