Refactor Z3 read callback.

This commit is contained in:
chriseth 2017-07-13 21:06:29 +02:00
parent 9ac2ac14c1
commit 1e05ebe50e
6 changed files with 46 additions and 133 deletions

View File

@ -17,7 +17,11 @@
#include <libsolidity/formal/SMTChecker.h>
#ifdef HAVE_Z3
#include <libsolidity/formal/Z3Interface.h>
#else
#include <libsolidity/formal/SMTLib2Interface.h>
#endif
#include <libsolidity/interface/ErrorReporter.h>
@ -25,10 +29,15 @@ using namespace std;
using namespace dev;
using namespace dev::solidity;
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadFile::Callback const& _readFileCallback):
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback):
#ifdef HAVE_Z3
m_interface(make_shared<smt::Z3Interface>()),
#else
m_interface(make_shared<smt::SMTLib2Interface>(_readFileCallback)),
#endif
m_errorReporter(_errorReporter)
{
(void)_readFileCallback;
}
void SMTChecker::analyze(SourceUnit const& _source)
@ -36,7 +45,7 @@ void SMTChecker::analyze(SourceUnit const& _source)
bool pragmaFound = false;
for (auto const& node: _source.nodes())
if (auto const* pragma = dynamic_cast<PragmaDirective const*>(node.get()))
if (pragma->literals()[0] == "checkAssertionsZ3")
if (pragma->literals()[0] == "checkAssertions")
pragmaFound = true;
if (pragmaFound)
{
@ -345,7 +354,19 @@ void SMTChecker::checkCondition(
}
smt::CheckResult result;
vector<string> values;
tie(result, values) = m_interface->check(expressionsToEvaluate);
try
{
tie(result, values) = m_interface->check(expressionsToEvaluate);
}
catch (smt::SolverError const& _e)
{
string description("Error querying SMT solver");
if (_e.comment())
description += ": " + *_e.comment();
m_errorReporter.warning(_location, description);
return;
}
switch (result)
{
case smt::CheckResult::SAT:

View File

@ -95,10 +95,11 @@ void SMTLib2Interface::addAssertion(Expression const& _expr)
pair<CheckResult, vector<string>> SMTLib2Interface::check(vector<Expression> const& _expressionsToEvaluate)
{
string response = m_communicator.communicate(
string response = querySolver(
boost::algorithm::join(m_accumulatedOutput, "\n") +
checkSatAndGetValuesCommand(_expressionsToEvaluate)
);
CheckResult result;
// TODO proper parsing
if (boost::starts_with(response, "sat\n"))
@ -173,3 +174,14 @@ vector<string> SMTLib2Interface::parseValues(string::const_iterator _start, stri
return values;
}
string SMTLib2Interface::querySolver(string const& _input)
{
if (!m_queryCallback)
BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment("No SMT solver available."));
ReadCallback::Result queryResult = m_queryCallback(_input);
if (!queryResult.success)
BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment(queryResult.responseOrErrorMessage));
return queryResult.responseOrErrorMessage;
}

View File

@ -17,7 +17,6 @@
#pragma once
#include <libsolidity/formal/SMTSolverCommunicator.h>
#include <libsolidity/formal/SolverInterface.h>
#include <libsolidity/interface/Exceptions.h>
@ -64,7 +63,10 @@ private:
std::string checkSatAndGetValuesCommand(std::vector<Expression> const& _expressionsToEvaluate);
std::vector<std::string> parseValues(std::string::const_iterator _start, std::string::const_iterator _end);
SMTSolverCommunicator m_communicator;
/// Communicates with the solver via the callback. Throws SMTSolverError on error.
std::string querySolver(std::string const& _input);
ReadCallback::Callback m_queryCallback;
std::vector<std::string> m_accumulatedOutput;
};

View File

@ -1,75 +0,0 @@
/*
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/SMTSolverCommunicator.h>
#include <libdevcore/Common.h>
#include <boost/filesystem/operations.hpp>
#include <fstream>
#include <stdio.h>
using namespace std;
using namespace dev;
using namespace dev::solidity::smt;
#ifdef EMSCRIPTEN
string SMTSolverCommunicator::communicate(string const& _input)
{
auto result = m_readFileCallback("SMTLIB2Solver>> " + _input);
if (result.success)
return result.contentsOrErrorMessage;
else
return "";
}
#else
#ifndef _WIN32
inline FILE* _popen(char const* command, char const* type)
{
return popen(command, type);
}
inline int _pclose(FILE* file)
{
return pclose(file);
}
#endif
string SMTSolverCommunicator::communicate(string const& _input)
{
namespace fs = boost::filesystem;
auto tempPath = fs::unique_path(fs::temp_directory_path() / "%%%%-%%%%-%%%%.smt2");
ScopeGuard s1([&]() { fs::remove(tempPath); });
ofstream(tempPath.string()) << _input << "(exit)" << endl;
// TODO Escaping might not be 100% perfect.
FILE* solverOutput = _popen(("z3 -smt2 \"" + tempPath.string() + "\"").c_str(), "r");
ScopeGuard s2([&]() { _pclose(solverOutput); });
string result;
array<char, 128> buffer;
while (!feof(solverOutput))
if (fgets(buffer.data(), 127, solverOutput) != nullptr)
result += buffer.data();
return result;
}
#endif

View File

@ -1,50 +0,0 @@
/*
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/interface/ReadFile.h>
#include <string>
namespace dev
{
namespace solidity
{
namespace smt
{
/// Platform-specific way to access the SMT solver.
class SMTSolverCommunicator
{
public:
/// Creates the communicator, the read file callback is used only
/// on the emscripten platform.
SMTSolverCommunicator(ReadFile::Callback const& _readFileCallback):
m_readFileCallback(_readFileCallback)
{}
std::string communicate(std::string const& _input);
private:
ReadFile::Callback m_readFileCallback;
};
}
}
}

View File

@ -17,12 +17,11 @@
#pragma once
#include <libsolidity/formal/SMTSolverCommunicator.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/ReadFile.h>
#include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h>
#include <boost/noncopyable.hpp>
@ -132,6 +131,8 @@ private:
Expression(std::move(_name), std::vector<Expression>{std::move(_arg1), std::move(_arg2)}) {}
};
DEV_SIMPLE_EXCEPTION(SolverError);
class SolverInterface
{
public:
@ -158,6 +159,8 @@ public:
virtual void addAssertion(Expression const& _expr) = 0;
/// Checks for satisfiability, evaluates the expressions if a model
/// is available. Throws SMTSolverError on error.
virtual std::pair<CheckResult, std::vector<std::string>>
check(std::vector<Expression> const& _expressionsToEvaluate) = 0;
};