From 71144d0d39dc545d9f9cf577be5969371a4d7aa5 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 3 Jul 2019 16:33:20 +0200 Subject: [PATCH] [CHCChecker] Add CHCSolverInterface and Z3CHCSolverInterface --- libsolidity/CMakeLists.txt | 3 +- libsolidity/formal/CHCSolverInterface.h | 56 ++++++++++++++ libsolidity/formal/Z3CHCInterface.cpp | 97 +++++++++++++++++++++++++ libsolidity/formal/Z3CHCInterface.h | 64 ++++++++++++++++ libsolidity/formal/Z3Interface.h | 13 +++- 5 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 libsolidity/formal/CHCSolverInterface.h create mode 100644 libsolidity/formal/Z3CHCInterface.cpp create mode 100644 libsolidity/formal/Z3CHCInterface.h diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index fdd7f616f..a376bba9f 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -77,6 +77,7 @@ set(sources codegen/ir/IRLValue.h formal/BMC.cpp formal/BMC.h + formal/CHCSolverInterface.h formal/EncodingContext.cpp formal/EncodingContext.h formal/ModelChecker.cpp @@ -121,7 +122,7 @@ find_package(Z3 4.6.0) if (${Z3_FOUND}) add_definitions(-DHAVE_Z3) message("Z3 SMT solver found. This enables optional SMT checking with Z3.") - set(z3_SRCS formal/Z3Interface.cpp formal/Z3Interface.h) + set(z3_SRCS formal/Z3Interface.cpp formal/Z3Interface.h formal/Z3CHCInterface.cpp formal/Z3CHCInterface.h) else() set(z3_SRCS) endif() diff --git a/libsolidity/formal/CHCSolverInterface.h b/libsolidity/formal/CHCSolverInterface.h new file mode 100644 index 000000000..091aa3d7c --- /dev/null +++ b/libsolidity/formal/CHCSolverInterface.h @@ -0,0 +1,56 @@ +/* + 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 . +*/ + +/** + * Interface for constrained Horn solvers. + */ + +#pragma once + +#include + +namespace dev +{ +namespace solidity +{ +namespace smt +{ + +class CHCSolverInterface +{ +public: + virtual ~CHCSolverInterface() = default; + + virtual void declareVariable(std::string const& _name, Sort const& _sort) = 0; + + /// Takes a function declaration as a relation. + virtual void registerRelation(Expression const& _expr) = 0; + + /// Takes an implication and adds as rule. + /// Needs to bound all vars as universally quantified. + virtual void addRule(Expression const& _expr, std::string const& _name) = 0; + + /// Takes a function application and checks + /// for reachability. + virtual std::pair> query( + Expression const& _expr + ) = 0; +}; + +} +} +} diff --git a/libsolidity/formal/Z3CHCInterface.cpp b/libsolidity/formal/Z3CHCInterface.cpp new file mode 100644 index 000000000..7b8de2c91 --- /dev/null +++ b/libsolidity/formal/Z3CHCInterface.cpp @@ -0,0 +1,97 @@ +/* + 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 . +*/ + +#include + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::solidity::smt; + +Z3CHCInterface::Z3CHCInterface(): + m_z3Interface(make_shared()), + m_context(m_z3Interface->context()), + m_solver(*m_context) +{ + // This needs to be set globally. + z3::set_param("rewriter.pull_cheap_ite", true); + // This needs to be set in the context. + m_context->set("timeout", queryTimeout); +} + +void Z3CHCInterface::declareVariable(string const& _name, Sort const& _sort) +{ + m_z3Interface->declareVariable(_name, _sort); +} + +void Z3CHCInterface::registerRelation(Expression const& _expr) +{ + m_solver.register_relation(m_z3Interface->functions().at(_expr.name)); +} + +void Z3CHCInterface::addRule(Expression const& _expr, string const& _name) +{ + z3::expr rule = m_z3Interface->toZ3Expr(_expr); + if (m_z3Interface->constants().empty()) + m_solver.add_rule(rule, m_context->str_symbol(_name.c_str())); + else + { + z3::expr_vector variables(*m_context); + for (auto const& var: m_z3Interface->constants()) + variables.push_back(var.second); + z3::expr boundRule = z3::forall(variables, rule); + m_solver.add_rule(boundRule, m_context->str_symbol(_name.c_str())); + } +} + +pair> Z3CHCInterface::query(Expression const& _expr) +{ + CheckResult result; + vector values; + try + { + z3::expr z3Expr = m_z3Interface->toZ3Expr(_expr); + switch (m_solver.query(z3Expr)) + { + case z3::check_result::sat: + { + result = CheckResult::SATISFIABLE; + // TODO retrieve model. + break; + } + case z3::check_result::unsat: + { + result = CheckResult::UNSATISFIABLE; + // TODO retrieve invariants. + break; + } + case z3::check_result::unknown: + result = CheckResult::UNKNOWN; + break; + } + // TODO retrieve model / invariants + } + catch (z3::exception const& _e) + { + result = CheckResult::ERROR; + values.clear(); + } + + return make_pair(result, values); +} diff --git a/libsolidity/formal/Z3CHCInterface.h b/libsolidity/formal/Z3CHCInterface.h new file mode 100644 index 000000000..a107ad424 --- /dev/null +++ b/libsolidity/formal/Z3CHCInterface.h @@ -0,0 +1,64 @@ +/* + 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 . +*/ + +/** + * Z3 specific Horn solver interface. + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace solidity +{ +namespace smt +{ + +class Z3CHCInterface: public CHCSolverInterface +{ +public: + Z3CHCInterface(); + + /// Forwards variable declaration to Z3Interface. + void declareVariable(std::string const& _name, Sort const& _sort) override; + + void registerRelation(Expression const& _expr) override; + + void addRule(Expression const& _expr, std::string const& _name) override; + + std::pair> query(Expression const& _expr) override; + + std::shared_ptr z3Interface() { return m_z3Interface; } + +private: + // Used to handle variables. + std::shared_ptr m_z3Interface; + + z3::context* m_context; + // Horn solver. + z3::fixedpoint m_solver; + + // SMT query timeout in milliseconds. + static int const queryTimeout = 10000; +}; + +} +} +} diff --git a/libsolidity/formal/Z3Interface.h b/libsolidity/formal/Z3Interface.h index ee4d1551d..171fdcaa5 100644 --- a/libsolidity/formal/Z3Interface.h +++ b/libsolidity/formal/Z3Interface.h @@ -43,17 +43,24 @@ public: void addAssertion(Expression const& _expr) override; std::pair> check(std::vector const& _expressionsToEvaluate) override; + z3::expr toZ3Expr(Expression const& _expr); + + std::map constants() const { return m_constants; } + std::map functions() const { return m_functions; } + + z3::context* context() { return &m_context; } + private: void declareFunction(std::string const& _name, Sort const& _sort); - z3::expr toZ3Expr(Expression const& _expr); z3::sort z3Sort(smt::Sort const& _sort); z3::sort_vector z3Sort(std::vector const& _sorts); - z3::context m_context; - z3::solver m_solver; std::map m_constants; std::map m_functions; + + z3::context m_context; + z3::solver m_solver; }; }