mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Warn when no solver was found and there are unhandled queries.
This commit is contained in:
parent
ebf503a67d
commit
9a33367bc6
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
|
|
||||||
@ -40,6 +42,11 @@ public:
|
|||||||
|
|
||||||
ErrorReporter& operator=(ErrorReporter const& _errorReporter);
|
ErrorReporter& operator=(ErrorReporter const& _errorReporter);
|
||||||
|
|
||||||
|
void append(ErrorList const& _errorList)
|
||||||
|
{
|
||||||
|
m_errorList += _errorList;
|
||||||
|
}
|
||||||
|
|
||||||
void warning(std::string const& _description);
|
void warning(std::string const& _description);
|
||||||
|
|
||||||
void warning(SourceLocation const& _location, std::string const& _description);
|
void warning(SourceLocation const& _location, std::string const& _description);
|
||||||
|
@ -34,7 +34,8 @@ using namespace dev::solidity;
|
|||||||
|
|
||||||
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, map<h256, string> const& _smtlib2Responses):
|
SMTChecker::SMTChecker(ErrorReporter& _errorReporter, map<h256, string> const& _smtlib2Responses):
|
||||||
m_interface(make_shared<smt::SMTPortfolio>(_smtlib2Responses)),
|
m_interface(make_shared<smt::SMTPortfolio>(_smtlib2Responses)),
|
||||||
m_errorReporter(_errorReporter)
|
m_errorReporterReference(_errorReporter),
|
||||||
|
m_errorReporter(m_smtErrors)
|
||||||
{
|
{
|
||||||
#if defined (HAVE_Z3) || defined (HAVE_CVC4)
|
#if defined (HAVE_Z3) || defined (HAVE_CVC4)
|
||||||
if (!_smtlib2Responses.empty())
|
if (!_smtlib2Responses.empty())
|
||||||
@ -53,6 +54,25 @@ void SMTChecker::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _
|
|||||||
m_scanner = _scanner;
|
m_scanner = _scanner;
|
||||||
if (_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
if (_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||||
_source.accept(*this);
|
_source.accept(*this);
|
||||||
|
|
||||||
|
solAssert(m_interface->solvers() > 0, "");
|
||||||
|
// If this check is true, Z3 and CVC4 are not available
|
||||||
|
// and the query answers were not provided, since SMTPortfolio
|
||||||
|
// guarantees that SmtLib2Interface is the first solver.
|
||||||
|
if (!m_interface->unhandledQueries().empty() && m_interface->solvers() == 1)
|
||||||
|
{
|
||||||
|
if (!m_noSolverWarning)
|
||||||
|
{
|
||||||
|
m_noSolverWarning = true;
|
||||||
|
m_errorReporterReference.warning(
|
||||||
|
SourceLocation(),
|
||||||
|
"SMTChecker analysis was not possible since no integrated SMT solver (Z3 or CVC4) was found."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporterReference.append(m_errorReporter.errors());
|
||||||
|
m_errorReporter.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SMTChecker::visit(ContractDefinition const& _contract)
|
bool SMTChecker::visit(ContractDefinition const& _contract)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
#include <libsolidity/interface/ReadFile.h>
|
#include <libsolidity/interface/ReadFile.h>
|
||||||
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/Scanner.h>
|
#include <liblangutil/Scanner.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -215,6 +216,8 @@ private:
|
|||||||
std::shared_ptr<VariableUsage> m_variableUsage;
|
std::shared_ptr<VariableUsage> m_variableUsage;
|
||||||
bool m_loopExecutionHappened = false;
|
bool m_loopExecutionHappened = false;
|
||||||
bool m_arrayAssignmentHappened = false;
|
bool m_arrayAssignmentHappened = false;
|
||||||
|
// True if the "No SMT solver available" warning was already created.
|
||||||
|
bool m_noSolverWarning = false;
|
||||||
/// An Expression may have multiple smt::Expression due to
|
/// An Expression may have multiple smt::Expression due to
|
||||||
/// repeated calls to the same function.
|
/// repeated calls to the same function.
|
||||||
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
|
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
|
||||||
@ -225,7 +228,13 @@ private:
|
|||||||
/// Used to retrieve models.
|
/// Used to retrieve models.
|
||||||
std::set<Expression const*> m_uninterpretedTerms;
|
std::set<Expression const*> m_uninterpretedTerms;
|
||||||
std::vector<smt::Expression> m_pathConditions;
|
std::vector<smt::Expression> m_pathConditions;
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
/// ErrorReporter that comes from CompilerStack.
|
||||||
|
langutil::ErrorReporter& m_errorReporterReference;
|
||||||
|
/// Local SMTChecker ErrorReporter.
|
||||||
|
/// This is necessary to show the "No SMT solver available"
|
||||||
|
/// warning before the others in case it's needed.
|
||||||
|
langutil::ErrorReporter m_errorReporter;
|
||||||
|
langutil::ErrorList m_smtErrors;
|
||||||
std::shared_ptr<langutil::Scanner> m_scanner;
|
std::shared_ptr<langutil::Scanner> m_scanner;
|
||||||
|
|
||||||
/// Stores the current path of function calls.
|
/// Stores the current path of function calls.
|
||||||
|
@ -129,6 +129,15 @@ pair<CheckResult, vector<string>> SMTPortfolio::check(vector<Expression> const&
|
|||||||
return make_pair(lastResult, finalValues);
|
return make_pair(lastResult, finalValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<string> SMTPortfolio::unhandledQueries()
|
||||||
|
{
|
||||||
|
// This code assumes that the constructor guarantees that
|
||||||
|
// SmtLib2Interface is in position 0.
|
||||||
|
solAssert(!m_solvers.empty(), "");
|
||||||
|
solAssert(dynamic_cast<smt::SMTLib2Interface*>(m_solvers.at(0).get()), "");
|
||||||
|
return m_solvers.at(0)->unhandledQueries();
|
||||||
|
}
|
||||||
|
|
||||||
bool SMTPortfolio::solverAnswered(CheckResult result)
|
bool SMTPortfolio::solverAnswered(CheckResult result)
|
||||||
{
|
{
|
||||||
return result == CheckResult::SATISFIABLE || result == CheckResult::UNSATISFIABLE;
|
return result == CheckResult::SATISFIABLE || result == CheckResult::UNSATISFIABLE;
|
||||||
|
@ -54,7 +54,8 @@ public:
|
|||||||
void addAssertion(Expression const& _expr) override;
|
void addAssertion(Expression const& _expr) override;
|
||||||
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
||||||
|
|
||||||
std::vector<std::string> unhandledQueries() override { return m_solvers.at(0)->unhandledQueries(); }
|
std::vector<std::string> unhandledQueries() override;
|
||||||
|
unsigned solvers() override { return m_solvers.size(); }
|
||||||
private:
|
private:
|
||||||
static bool solverAnswered(CheckResult result);
|
static bool solverAnswered(CheckResult result);
|
||||||
|
|
||||||
|
@ -305,6 +305,9 @@ public:
|
|||||||
/// @returns a list of queries that the system was not able to respond to.
|
/// @returns a list of queries that the system was not able to respond to.
|
||||||
virtual std::vector<std::string> unhandledQueries() { return {}; }
|
virtual std::vector<std::string> unhandledQueries() { return {}; }
|
||||||
|
|
||||||
|
/// @returns how many SMT solvers this interface has.
|
||||||
|
virtual unsigned solvers() { return 1; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// SMT query timeout in milliseconds.
|
// SMT query timeout in milliseconds.
|
||||||
static int const queryTimeout = 10000;
|
static int const queryTimeout = 10000;
|
||||||
|
Loading…
Reference in New Issue
Block a user