mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Convert z3 cex graph into STL
This commit is contained in:
parent
a7a069c74a
commit
744905525f
@ -83,7 +83,7 @@ void CHCSmtLib2Interface::addRule(Expression const& _expr, std::string const& _n
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<CheckResult, vector<string>> CHCSmtLib2Interface::query(Expression const& _block)
|
pair<CheckResult, CHCSolverInterface::CexGraph> CHCSmtLib2Interface::query(Expression const& _block)
|
||||||
{
|
{
|
||||||
string accumulated{};
|
string accumulated{};
|
||||||
swap(m_accumulatedOutput, accumulated);
|
swap(m_accumulatedOutput, accumulated);
|
||||||
@ -108,7 +108,7 @@ pair<CheckResult, vector<string>> CHCSmtLib2Interface::query(Expression const& _
|
|||||||
result = CheckResult::ERROR;
|
result = CheckResult::ERROR;
|
||||||
|
|
||||||
// TODO collect invariants or counterexamples.
|
// TODO collect invariants or counterexamples.
|
||||||
return make_pair(result, vector<string>{});
|
return {result, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHCSmtLib2Interface::declareVariable(string const& _name, SortPointer const& _sort)
|
void CHCSmtLib2Interface::declareVariable(string const& _name, SortPointer const& _sort)
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
|
|
||||||
void addRule(Expression const& _expr, std::string const& _name) override;
|
void addRule(Expression const& _expr, std::string const& _name) override;
|
||||||
|
|
||||||
std::pair<CheckResult, std::vector<std::string>> query(Expression const& _expr) override;
|
std::pair<CheckResult, CexGraph> query(Expression const& _expr) override;
|
||||||
|
|
||||||
void declareVariable(std::string const& _name, SortPointer const& _sort) override;
|
void declareVariable(std::string const& _name, SortPointer const& _sort) override;
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
#include <libsmtutil/SolverInterface.h>
|
#include <libsmtutil/SolverInterface.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace solidity::smtutil
|
namespace solidity::smtutil
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -41,9 +44,18 @@ public:
|
|||||||
/// Needs to bound all vars as universally quantified.
|
/// Needs to bound all vars as universally quantified.
|
||||||
virtual void addRule(Expression const& _expr, std::string const& _name) = 0;
|
virtual void addRule(Expression const& _expr, std::string const& _name) = 0;
|
||||||
|
|
||||||
/// Takes a function application and checks
|
/// first: predicate name
|
||||||
/// for reachability.
|
/// second: predicate arguments
|
||||||
virtual std::pair<CheckResult, std::vector<std::string>> query(
|
using CexNode = std::pair<std::string, std::vector<std::string>>;
|
||||||
|
struct CexGraph
|
||||||
|
{
|
||||||
|
std::map<unsigned, CexNode> nodes;
|
||||||
|
std::map<unsigned, std::vector<unsigned>> edges;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Takes a function application _expr and checks for reachability.
|
||||||
|
/// @returns solving result and a counterexample graph, if possible.
|
||||||
|
virtual std::pair<CheckResult, CexGraph> query(
|
||||||
Expression const& _expr
|
Expression const& _expr
|
||||||
) = 0;
|
) = 0;
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#include <libsolutil/CommonIO.h>
|
#include <libsolutil/CommonIO.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::smtutil;
|
using namespace solidity::smtutil;
|
||||||
@ -43,6 +46,7 @@ Z3CHCInterface::Z3CHCInterface():
|
|||||||
p.set("fp.spacer.mbqi", false);
|
p.set("fp.spacer.mbqi", false);
|
||||||
// Ground pobs by using values from a model.
|
// Ground pobs by using values from a model.
|
||||||
p.set("fp.spacer.ground_pobs", false);
|
p.set("fp.spacer.ground_pobs", false);
|
||||||
|
|
||||||
m_solver.set(p);
|
m_solver.set(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,10 +76,10 @@ void Z3CHCInterface::addRule(Expression const& _expr, string const& _name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<CheckResult, vector<string>> Z3CHCInterface::query(Expression const& _expr)
|
pair<CheckResult, CHCSolverInterface::CexGraph> Z3CHCInterface::query(Expression const& _expr)
|
||||||
{
|
{
|
||||||
CheckResult result;
|
CheckResult result;
|
||||||
vector<string> values;
|
CHCSolverInterface::CexGraph cex;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
z3::expr z3Expr = m_z3Interface->toZ3Expr(_expr);
|
z3::expr z3Expr = m_z3Interface->toZ3Expr(_expr);
|
||||||
@ -84,8 +88,9 @@ pair<CheckResult, vector<string>> Z3CHCInterface::query(Expression const& _expr)
|
|||||||
case z3::check_result::sat:
|
case z3::check_result::sat:
|
||||||
{
|
{
|
||||||
result = CheckResult::SATISFIABLE;
|
result = CheckResult::SATISFIABLE;
|
||||||
// TODO retrieve model.
|
auto proof = m_solver.get_answer();
|
||||||
break;
|
auto cex = cexGraph(proof);
|
||||||
|
return {result, cex};
|
||||||
}
|
}
|
||||||
case z3::check_result::unsat:
|
case z3::check_result::unsat:
|
||||||
{
|
{
|
||||||
@ -104,8 +109,89 @@ pair<CheckResult, vector<string>> Z3CHCInterface::query(Expression const& _expr)
|
|||||||
catch (z3::exception const&)
|
catch (z3::exception const&)
|
||||||
{
|
{
|
||||||
result = CheckResult::ERROR;
|
result = CheckResult::ERROR;
|
||||||
values.clear();
|
cex = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_pair(result, values);
|
return {result, cex};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convert a ground refutation into a linear or nonlinear counterexample.
|
||||||
|
The counterexample is given as an implication graph of the form
|
||||||
|
`premises => conclusion` where `premises` are the predicates
|
||||||
|
from the body of nonlinear clauses, representing the proof graph.
|
||||||
|
*/
|
||||||
|
CHCSolverInterface::CexGraph Z3CHCInterface::cexGraph(z3::expr const& _proof)
|
||||||
|
{
|
||||||
|
CexGraph graph;
|
||||||
|
|
||||||
|
/// The root fact of the refutation proof is `false`.
|
||||||
|
/// The node itself is not a hyper resolution, so we need to
|
||||||
|
/// extract the `query` hyper resolution node from the
|
||||||
|
/// `false` node (the first child).
|
||||||
|
smtAssert(_proof.is_app(), "");
|
||||||
|
smtAssert(fact(_proof).decl().decl_kind() == Z3_OP_FALSE, "");
|
||||||
|
|
||||||
|
stack<z3::expr> proofStack;
|
||||||
|
proofStack.push(_proof.arg(0));
|
||||||
|
|
||||||
|
auto const& root = proofStack.top();
|
||||||
|
graph.nodes[root.id()] = {name(fact(root)), arguments(fact(root))};
|
||||||
|
|
||||||
|
set<unsigned> visited;
|
||||||
|
visited.insert(root.id());
|
||||||
|
|
||||||
|
while (!proofStack.empty())
|
||||||
|
{
|
||||||
|
z3::expr proofNode = proofStack.top();
|
||||||
|
smtAssert(graph.nodes.count(proofNode.id()), "");
|
||||||
|
proofStack.pop();
|
||||||
|
|
||||||
|
if (proofNode.is_app() && proofNode.decl().decl_kind() == Z3_OP_PR_HYPER_RESOLVE)
|
||||||
|
{
|
||||||
|
smtAssert(proofNode.num_args() > 0, "");
|
||||||
|
for (unsigned i = 1; i < proofNode.num_args() - 1; ++i)
|
||||||
|
{
|
||||||
|
z3::expr child = proofNode.arg(i);
|
||||||
|
if (!visited.count(child.id()))
|
||||||
|
{
|
||||||
|
visited.insert(child.id());
|
||||||
|
proofStack.push(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!graph.nodes.count(child.id()))
|
||||||
|
{
|
||||||
|
graph.nodes[child.id()] = {name(fact(child)), arguments(fact(child))};
|
||||||
|
graph.edges[child.id()] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.edges[proofNode.id()].push_back(child.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
z3::expr Z3CHCInterface::fact(z3::expr const& _node)
|
||||||
|
{
|
||||||
|
smtAssert(_node.is_app(), "");
|
||||||
|
if (_node.num_args() == 0)
|
||||||
|
return _node;
|
||||||
|
return _node.arg(_node.num_args() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string Z3CHCInterface::name(z3::expr const& _predicate)
|
||||||
|
{
|
||||||
|
smtAssert(_predicate.is_app(), "");
|
||||||
|
return _predicate.decl().name().str();
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> Z3CHCInterface::arguments(z3::expr const& _predicate)
|
||||||
|
{
|
||||||
|
smtAssert(_predicate.is_app(), "");
|
||||||
|
vector<string> args;
|
||||||
|
for (unsigned i = 0; i < _predicate.num_args(); ++i)
|
||||||
|
args.emplace_back(_predicate.arg(i).to_string());
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <libsmtutil/CHCSolverInterface.h>
|
#include <libsmtutil/CHCSolverInterface.h>
|
||||||
#include <libsmtutil/Z3Interface.h>
|
#include <libsmtutil/Z3Interface.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace solidity::smtutil
|
namespace solidity::smtutil
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -40,11 +42,20 @@ public:
|
|||||||
|
|
||||||
void addRule(Expression const& _expr, std::string const& _name) override;
|
void addRule(Expression const& _expr, std::string const& _name) override;
|
||||||
|
|
||||||
std::pair<CheckResult, std::vector<std::string>> query(Expression const& _expr) override;
|
std::pair<CheckResult, CexGraph> query(Expression const& _expr) override;
|
||||||
|
|
||||||
Z3Interface* z3Interface() const { return m_z3Interface.get(); }
|
Z3Interface* z3Interface() const { return m_z3Interface.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Constructs a nonlinear counterexample graph from the refutation.
|
||||||
|
CHCSolverInterface::CexGraph cexGraph(z3::expr const& _proof);
|
||||||
|
/// @returns the fact from a proof node.
|
||||||
|
z3::expr fact(z3::expr const& _node);
|
||||||
|
/// @returns @a _predicate's name.
|
||||||
|
std::string name(z3::expr const& _predicate);
|
||||||
|
/// @returns the arguments of @a _predicate.
|
||||||
|
std::vector<std::string> arguments(z3::expr const& _predicate);
|
||||||
|
|
||||||
// Used to handle variables.
|
// Used to handle variables.
|
||||||
std::unique_ptr<Z3Interface> m_z3Interface;
|
std::unique_ptr<Z3Interface> m_z3Interface;
|
||||||
|
|
||||||
|
@ -1103,11 +1103,11 @@ void CHC::addRule(smtutil::Expression const& _rule, string const& _ruleName)
|
|||||||
m_interface->addRule(_rule, _ruleName);
|
m_interface->addRule(_rule, _ruleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<smtutil::CheckResult, vector<string>> CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location)
|
pair<smtutil::CheckResult, CHCSolverInterface::CexGraph> CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
smtutil::CheckResult result;
|
smtutil::CheckResult result;
|
||||||
vector<string> values;
|
CHCSolverInterface::CexGraph cex;
|
||||||
tie(result, values) = m_interface->query(_query);
|
tie(result, cex) = m_interface->query(_query);
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case smtutil::CheckResult::SATISFIABLE:
|
case smtutil::CheckResult::SATISFIABLE:
|
||||||
@ -1123,7 +1123,7 @@ pair<smtutil::CheckResult, vector<string>> CHC::query(smtutil::Expression const&
|
|||||||
m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver.");
|
m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return {result, values};
|
return {result, cex};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHC::addVerificationTarget(
|
void CHC::addVerificationTarget(
|
||||||
|
@ -192,7 +192,7 @@ private:
|
|||||||
void addRule(smtutil::Expression const& _rule, std::string const& _ruleName);
|
void addRule(smtutil::Expression const& _rule, std::string const& _ruleName);
|
||||||
/// @returns <true, empty> if query is unsatisfiable (safe).
|
/// @returns <true, empty> if query is unsatisfiable (safe).
|
||||||
/// @returns <false, model> otherwise.
|
/// @returns <false, model> otherwise.
|
||||||
std::pair<smtutil::CheckResult, std::vector<std::string>> query(smtutil::Expression const& _query, langutil::SourceLocation const& _location);
|
std::pair<smtutil::CheckResult, smtutil::CHCSolverInterface::CexGraph> query(smtutil::Expression const& _query, langutil::SourceLocation const& _location);
|
||||||
|
|
||||||
void addVerificationTarget(ASTNode const* _scope, VerificationTarget::Type _type, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId);
|
void addVerificationTarget(ASTNode const* _scope, VerificationTarget::Type _type, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId);
|
||||||
void addAssertVerificationTarget(ASTNode const* _scope, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId);
|
void addAssertVerificationTarget(ASTNode const* _scope, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId);
|
||||||
|
Loading…
Reference in New Issue
Block a user