Skip to content

Commit 24df40d

Browse files
author
Leo Alt
committed
Allow running Eldarica from the command line
1 parent be8ecb1 commit 24df40d

File tree

67 files changed

+384
-3185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+384
-3185
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Compiler Features:
1313
* Yul Optimizer: Allow replacing the previously hard-coded cleanup sequence by specifying custom steps after a colon delimiter (``:``) in the sequence string.
1414
* Language Server: Add basic document hover support.
1515
* Optimizer: Added optimization rule ``and(shl(X, Y), shl(X, Z)) => shl(X, and(Y, Z))``.
16+
* SMTChecker: Support Eldarica as a Horn solver for the CHC engine when using the CLI option ``--model-checker-solvers eld``. The binary `eld` must be available in the system.
17+
* SMTChecker: Make ``z3`` the default solver for the BMC and CHC engines instead of all solvers.
1618

1719

1820
Bugfixes:

docs/smtchecker.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,19 +614,19 @@ which is primarily an SMT solver and makes `Spacer
614614
<https://github.com/uuverifiers/eldarica>`_ which does both.
615615

616616
The user can choose which solvers should be used, if available, via the CLI
617-
option ``--model-checker-solvers {all,cvc4,smtlib2,z3}`` or the JSON option
617+
option ``--model-checker-solvers {all,cvc4,eld,smtlib2,z3}`` or the JSON option
618618
``settings.modelChecker.solvers=[smtlib2,z3]``, where:
619619

620620
- ``cvc4`` is only available if the ``solc`` binary is compiled with it. Only BMC uses ``cvc4``.
621+
- ``eld`` is used via its binary which must be installed in the system. Only CHC uses ``eld``, and only if ``z3`` is not enabled.
621622
- ``smtlib2`` outputs SMT/Horn queries in the `smtlib2 <http://smtlib.cs.uiowa.edu/>`_ format.
622623
These can be used together with the compiler's `callback mechanism <https://github.com/ethereum/solc-js>`_ so that
623624
any solver binary from the system can be employed to synchronously return the results of the queries to the compiler.
624-
This is currently the only way to use Eldarica, for example, since it does not have a C++ API.
625625
This can be used by both BMC and CHC depending on which solvers are called.
626626
- ``z3`` is available
627627

628628
- if ``solc`` is compiled with it;
629-
- if a dynamic ``z3`` library of version 4.8.x is installed in a Linux system (from Solidity 0.7.6);
629+
- if a dynamic ``z3`` library of version >=4.8.x is installed in a Linux system (from Solidity 0.7.6);
630630
- statically in ``soljson.js`` (from Solidity 0.6.9), that is, the Javascript binary of the compiler.
631631

632632
.. note::

libsmtutil/CHCSmtLib2Interface.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ using namespace solidity::smtutil;
4040
CHCSmtLib2Interface::CHCSmtLib2Interface(
4141
map<h256, string> const& _queryResponses,
4242
ReadCallback::Callback _smtCallback,
43+
SMTSolverChoice _enabledSolvers,
4344
optional<unsigned> _queryTimeout
4445
):
4546
CHCSolverInterface(_queryTimeout),
4647
m_smtlib2(make_unique<SMTLib2Interface>(_queryResponses, _smtCallback, m_queryTimeout)),
4748
m_queryResponses(std::move(_queryResponses)),
48-
m_smtCallback(_smtCallback)
49+
m_smtCallback(_smtCallback),
50+
m_enabledSolvers(_enabledSolvers)
4951
{
5052
reset();
5153
}
@@ -203,12 +205,15 @@ string CHCSmtLib2Interface::querySolver(string const& _input)
203205
util::h256 inputHash = util::keccak256(_input);
204206
if (m_queryResponses.count(inputHash))
205207
return m_queryResponses.at(inputHash);
208+
209+
smtAssert(m_enabledSolvers.smtlib2 || m_enabledSolvers.eld);
206210
if (m_smtCallback)
207211
{
208212
auto result = m_smtCallback(ReadCallback::kindString(ReadCallback::Kind::SMTQuery), _input);
209213
if (result.success)
210214
return result.responseOrErrorMessage;
211215
}
216+
212217
m_unhandledQueries.push_back(_input);
213218
return "unknown\n";
214219
}

libsmtutil/CHCSmtLib2Interface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CHCSmtLib2Interface: public CHCSolverInterface
3535
explicit CHCSmtLib2Interface(
3636
std::map<util::h256, std::string> const& _queryResponses = {},
3737
frontend::ReadCallback::Callback _smtCallback = {},
38+
SMTSolverChoice _enabledSolvers = SMTSolverChoice::All(),
3839
std::optional<unsigned> _queryTimeout = {}
3940
);
4041

@@ -78,6 +79,7 @@ class CHCSmtLib2Interface: public CHCSolverInterface
7879
std::vector<std::string> m_unhandledQueries;
7980

8081
frontend::ReadCallback::Callback m_smtCallback;
82+
SMTSolverChoice m_enabledSolvers;
8183

8284
std::map<Sort const*, std::string> m_sortNames;
8385
};

libsmtutil/SolverInterface.h

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,35 +42,31 @@ namespace solidity::smtutil
4242
struct SMTSolverChoice
4343
{
4444
bool cvc4 = false;
45+
bool eld = false;
4546
bool smtlib2 = false;
4647
bool z3 = false;
4748

48-
static constexpr SMTSolverChoice All() noexcept { return {true, true, true}; }
49-
static constexpr SMTSolverChoice CVC4() noexcept { return {true, false, false}; }
50-
static constexpr SMTSolverChoice SMTLIB2() noexcept { return {false, true, false}; }
51-
static constexpr SMTSolverChoice Z3() noexcept { return {false, false, true}; }
52-
static constexpr SMTSolverChoice None() noexcept { return {false, false, false}; }
49+
static constexpr SMTSolverChoice All() noexcept { return {true, true, true, true}; }
50+
static constexpr SMTSolverChoice CVC4() noexcept { return {true, false, false, false}; }
51+
static constexpr SMTSolverChoice ELD() noexcept { return {false, true, false, false}; }
52+
static constexpr SMTSolverChoice SMTLIB2() noexcept { return {false, false, true, false}; }
53+
static constexpr SMTSolverChoice Z3() noexcept { return {false, false, false, true}; }
54+
static constexpr SMTSolverChoice None() noexcept { return {false, false, false, false}; }
5355

5456
static std::optional<SMTSolverChoice> fromString(std::string const& _solvers)
5557
{
5658
SMTSolverChoice solvers;
57-
if (_solvers == "all")
58-
{
59-
smtAssert(solvers.setSolver("cvc4"), "");
60-
smtAssert(solvers.setSolver("smtlib2"), "");
61-
smtAssert(solvers.setSolver("z3"), "");
62-
}
63-
else
64-
for (auto&& s: _solvers | ranges::views::split(',') | ranges::to<std::vector<std::string>>())
65-
if (!solvers.setSolver(s))
66-
return {};
59+
for (auto&& s: _solvers | ranges::views::split(',') | ranges::to<std::vector<std::string>>())
60+
if (!solvers.setSolver(s))
61+
return {};
6762

6863
return solvers;
6964
}
7065

7166
SMTSolverChoice& operator&=(SMTSolverChoice const& _other)
7267
{
7368
cvc4 &= _other.cvc4;
69+
eld &= _other.eld;
7470
smtlib2 &= _other.smtlib2;
7571
z3 &= _other.z3;
7672
return *this;
@@ -87,17 +83,20 @@ struct SMTSolverChoice
8783
bool operator==(SMTSolverChoice const& _other) const noexcept
8884
{
8985
return cvc4 == _other.cvc4 &&
86+
eld == _other.eld &&
9087
smtlib2 == _other.smtlib2 &&
9188
z3 == _other.z3;
9289
}
9390

9491
bool setSolver(std::string const& _solver)
9592
{
96-
static std::set<std::string> const solvers{"cvc4", "smtlib2", "z3"};
93+
static std::set<std::string> const solvers{"cvc4", "eld", "smtlib2", "z3"};
9794
if (!solvers.count(_solver))
9895
return false;
9996
if (_solver == "cvc4")
10097
cvc4 = true;
98+
if (_solver == "eld")
99+
eld = true;
101100
else if (_solver == "smtlib2")
102101
smtlib2 = true;
103102
else if (_solver == "z3")
@@ -106,8 +105,8 @@ struct SMTSolverChoice
106105
}
107106

108107
bool none() const noexcept { return !some(); }
109-
bool some() const noexcept { return cvc4 || smtlib2 || z3; }
110-
bool all() const noexcept { return cvc4 && smtlib2 && z3; }
108+
bool some() const noexcept { return cvc4 || eld || smtlib2 || z3; }
109+
bool all() const noexcept { return cvc4 && eld && smtlib2 && z3; }
111110
};
112111

113112
enum class CheckResult

libsolidity/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,13 @@ set(sources
149149
interface/Natspec.h
150150
interface/OptimiserSettings.h
151151
interface/ReadFile.h
152+
interface/SMTSolverCommand.cpp
153+
interface/SMTSolverCommand.h
152154
interface/StandardCompiler.cpp
153155
interface/StandardCompiler.h
154156
interface/StorageLayout.cpp
155157
interface/StorageLayout.h
158+
interface/UniversalCallback.h
156159
interface/Version.cpp
157160
interface/Version.h
158161
lsp/DocumentHoverHandler.cpp
@@ -181,5 +184,5 @@ set(sources
181184
)
182185

183186
add_library(solidity ${sources})
184-
target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only)
187+
target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only Threads::Threads)
185188

libsolidity/formal/BMC.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <libsolidity/formal/BMC.h>
2020

21+
#include <libsolidity/formal/ModelChecker.h>
2122
#include <libsolidity/formal/SymbolicTypes.h>
2223

2324
#include <libsmtutil/SMTPortfolio.h>
@@ -40,7 +41,7 @@ BMC::BMC(
4041
UniqueErrorReporter& _errorReporter,
4142
map<h256, string> const& _smtlib2Responses,
4243
ReadCallback::Callback const& _smtCallback,
43-
ModelCheckerSettings const& _settings,
44+
ModelCheckerSettings _settings,
4445
CharStreamProvider const& _charStreamProvider
4546
):
4647
SMTEncoder(_context, _settings, _errorReporter, _charStreamProvider),
@@ -61,15 +62,14 @@ BMC::BMC(
6162

6263
void BMC::analyze(SourceUnit const& _source, map<ASTNode const*, set<VerificationTargetType>, smt::EncodingContext::IdCompare> _solvedTargets)
6364
{
64-
if (m_interface->solvers() == 0)
65+
// At this point every enabled solver is available.
66+
if (!m_settings.solvers.cvc4 && !m_settings.solvers.smtlib2 && !m_settings.solvers.z3)
6567
{
6668
m_errorReporter.warning(
6769
7710_error,
6870
SourceLocation(),
6971
"BMC analysis was not possible since no SMT solver was found and enabled."
70-
#ifdef HAVE_Z3_DLOPEN
71-
" Install libz3.so." + to_string(Z3_MAJOR_VERSION) + "." + to_string(Z3_MINOR_VERSION) + " to enable Z3."
72-
#endif
72+
" The accepted solvers for BMC are cvc4 and z3."
7373
);
7474
return;
7575
}

libsolidity/formal/BMC.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class BMC: public SMTEncoder
6262
langutil::UniqueErrorReporter& _errorReporter,
6363
std::map<h256, std::string> const& _smtlib2Responses,
6464
ReadCallback::Callback const& _smtCallback,
65-
ModelCheckerSettings const& _settings,
65+
ModelCheckerSettings _settings,
6666
langutil::CharStreamProvider const& _charStreamProvider
6767
);
6868

libsolidity/formal/CHC.cpp

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include <libsolidity/formal/CHC.h>
2020

21+
#include <libsolidity/formal/ModelChecker.h>
22+
2123
#ifdef HAVE_Z3
2224
#include <libsmtutil/Z3CHCInterface.h>
2325
#endif
@@ -62,7 +64,7 @@ CHC::CHC(
6264
UniqueErrorReporter& _errorReporter,
6365
map<util::h256, string> const& _smtlib2Responses,
6466
ReadCallback::Callback const& _smtCallback,
65-
ModelCheckerSettings const& _settings,
67+
ModelCheckerSettings _settings,
6668
CharStreamProvider const& _charStreamProvider
6769
):
6870
SMTEncoder(_context, _settings, _errorReporter, _charStreamProvider),
@@ -73,31 +75,29 @@ CHC::CHC(
7375

7476
void CHC::analyze(SourceUnit const& _source)
7577
{
76-
if (!shouldAnalyze(_source))
77-
return;
78-
79-
bool usesZ3 = m_settings.solvers.z3;
80-
#ifdef HAVE_Z3_DLOPEN
81-
if (m_settings.solvers.z3 && !Z3Interface::available())
78+
// At this point every enabled solver is available.
79+
if (!m_settings.solvers.eld && !m_settings.solvers.smtlib2 && !m_settings.solvers.z3)
8280
{
83-
usesZ3 = false;
8481
m_errorReporter.warning(
85-
8158_error,
82+
7649_error,
8683
SourceLocation(),
87-
"z3 was selected as a Horn solver for CHC analysis but libz3.so." + to_string(Z3_MAJOR_VERSION) + "." + to_string(Z3_MINOR_VERSION) + " was not found."
84+
"CHC analysis was not possible since no Horn solver was found and enabled."
85+
" The accepted solvers for CHC are Eldarica and z3."
8886
);
87+
return;
8988
}
90-
#endif
9189

92-
if (!usesZ3 && !m_settings.solvers.smtlib2)
93-
{
90+
if (m_settings.solvers.eld && m_settings.solvers.z3)
9491
m_errorReporter.warning(
95-
7649_error,
92+
5798_error,
9693
SourceLocation(),
97-
"CHC analysis was not possible since no Horn solver was found and enabled."
94+
"Multiple Horn solvers were selected for CHC."
95+
" CHC only supports one solver at a time, therefore only z3 will be used."
96+
" If you wish to use Eldarica, please enable Eldarica only."
9897
);
98+
99+
if (!shouldAnalyze(_source))
99100
return;
100-
}
101101

102102
resetSourceAnalysis();
103103

@@ -115,7 +115,8 @@ void CHC::analyze(SourceUnit const& _source)
115115

116116
bool ranSolver = true;
117117
// If ranSolver is true here it's because an SMT solver callback was
118-
// actually given and the queries were solved.
118+
// actually given and the queries were solved,
119+
// or Eldarica was chosen and was present in the system.
119120
if (auto const* smtLibInterface = dynamic_cast<CHCSmtLib2Interface const*>(m_interface.get()))
120121
ranSolver = smtLibInterface->unhandledQueries().empty();
121122
if (!ranSolver)
@@ -994,24 +995,27 @@ void CHC::resetSourceAnalysis()
994995
ArraySlicePredicate::reset();
995996
m_blockCounter = 0;
996997

997-
bool usesZ3 = false;
998-
#ifdef HAVE_Z3
999-
usesZ3 = m_settings.solvers.z3 && Z3Interface::available();
1000-
if (usesZ3)
998+
// At this point every enabled solver is available.
999+
// If more than one Horn solver is selected we go with z3.
1000+
// We still need the ifdef because of Z3CHCInterface.
1001+
if (m_settings.solvers.z3)
10011002
{
1002-
/// z3::fixedpoint does not have a reset mechanism, so we need to create another.
1003+
#ifdef HAVE_Z3
1004+
// z3::fixedpoint does not have a reset mechanism, so we need to create another.
10031005
m_interface = std::make_unique<Z3CHCInterface>(m_settings.timeout);
10041006
auto z3Interface = dynamic_cast<Z3CHCInterface const*>(m_interface.get());
10051007
solAssert(z3Interface, "");
10061008
m_context.setSolver(z3Interface->z3Interface());
1007-
}
1009+
#else
1010+
solAssert(false);
10081011
#endif
1009-
if (!usesZ3)
1012+
}
1013+
if (!m_settings.solvers.z3)
10101014
{
1011-
solAssert(m_settings.solvers.smtlib2);
1015+
solAssert(m_settings.solvers.smtlib2 || m_settings.solvers.eld);
10121016

10131017
if (!m_interface)
1014-
m_interface = make_unique<CHCSmtLib2Interface>(m_smtlib2Responses, m_smtCallback, m_settings.timeout);
1018+
m_interface = make_unique<CHCSmtLib2Interface>(m_smtlib2Responses, m_smtCallback, m_settings.solvers, m_settings.timeout);
10151019

10161020
auto smtlib2Interface = dynamic_cast<CHCSmtLib2Interface*>(m_interface.get());
10171021
solAssert(smtlib2Interface, "");
@@ -1551,9 +1555,10 @@ tuple<CheckResult, smtutil::Expression, CHCSolverInterface::CexGraph> CHC::query
15511555
{
15521556
case CheckResult::SATISFIABLE:
15531557
{
1554-
#ifdef HAVE_Z3
1558+
// We still need the ifdef because of Z3CHCInterface.
15551559
if (m_settings.solvers.z3)
15561560
{
1561+
#ifdef HAVE_Z3
15571562
// Even though the problem is SAT, Spacer's pre processing makes counterexamples incomplete.
15581563
// We now disable those optimizations and check whether we can still solve the problem.
15591564
auto* spacer = dynamic_cast<Z3CHCInterface*>(m_interface.get());
@@ -1569,8 +1574,10 @@ tuple<CheckResult, smtutil::Expression, CHCSolverInterface::CexGraph> CHC::query
15691574
cex = std::move(cexNoOpt);
15701575

15711576
spacer->setSpacerOptions(true);
1572-
}
1577+
#else
1578+
solAssert(false);
15731579
#endif
1580+
}
15741581
break;
15751582
}
15761583
case CheckResult::UNSATISFIABLE:

libsolidity/formal/CHC.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class CHC: public SMTEncoder
5959
langutil::UniqueErrorReporter& _errorReporter,
6060
std::map<util::h256, std::string> const& _smtlib2Responses,
6161
ReadCallback::Callback const& _smtCallback,
62-
ModelCheckerSettings const& _settings,
62+
ModelCheckerSettings _settings,
6363
langutil::CharStreamProvider const& _charStreamProvider
6464
);
6565

0 commit comments

Comments
 (0)