Skip to content

Commit 8f1645b

Browse files
author
Leo Alt
committed
tests
1 parent b8a942f commit 8f1645b

File tree

138 files changed

+281
-156
lines changed

Some content is hidden

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

138 files changed

+281
-156
lines changed

libsolidity/formal/CHC.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,15 +1722,24 @@ void CHC::checkVerificationTargets()
17221722
" Consider increasing the timeout per query."
17231723
);
17241724

1725-
if (m_settings.invariants)
1726-
for (auto const& [node, invs]: m_invariants)
1725+
if (!m_settings.invariants.invariants.empty())
1726+
for (auto const& [pred, invs]: m_invariants)
17271727
{
1728+
ASTNode const* node = pred->programNode();
17281729
string what;
17291730
if (auto contract = dynamic_cast<ContractDefinition const*>(node))
17301731
what = contract->fullyQualifiedName();
1731-
string msg = "Contract invariants and external call properties for " + what + ":\n";
1732+
string msg = "Inferred inductive properties for " + what + ":\n";
17321733
for (auto const& inv: invs)
1733-
msg += inv + "\n";
1734+
{
1735+
string invType;
1736+
if (pred->type() == PredicateType::Interface)
1737+
invType = "Contract invariant";
1738+
else if (pred->type() == PredicateType::NondetInterface)
1739+
invType = "Reentrancy property";
1740+
solAssert(!invType.empty(), "");
1741+
msg += invType + ": " + inv + "\n";
1742+
}
17341743
m_errorReporter.info(
17351744
1180_error,
17361745
node->location(),
@@ -1780,8 +1789,8 @@ void CHC::checkAndReportTarget(
17801789
predicates.insert(pred);
17811790
for (auto const* pred: m_nondetInterfaces | ranges::views::values)
17821791
predicates.insert(pred);
1783-
for (auto const& [node, invs]: collectInvariants(invariant, predicates))
1784-
m_invariants[node] += invs;
1792+
for (auto&& [pred, invs]: collectInvariants(invariant, predicates, m_settings.invariants))
1793+
m_invariants[pred] += move(invs);
17851794
}
17861795
else if (result == CheckResult::SATISFIABLE)
17871796
{

libsolidity/formal/CHC.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ class CHC: public SMTEncoder
380380
std::map<ASTNode const*, std::map<VerificationTargetType, ReportTargetInfo>, smt::EncodingContext::IdCompare> m_unprovedTargets;
381381

382382
/// Inferred invariants.
383-
std::map<ASTNode const*, std::set<std::string>, smt::EncodingContext::IdCompare> m_invariants;
383+
std::map<Predicate const*, std::set<std::string>, PredicateCompare> m_invariants;
384384
//@}
385385

386386
/// Control-flow.

libsolidity/formal/Invariants.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,18 @@ using namespace solidity::frontend::smt;
3434
namespace solidity::frontend::smt
3535
{
3636

37-
map<ASTNode const*, set<string>> collectInvariants(smtutil::Expression const& _proof, set<Predicate const*> const& _predicates)
37+
map<Predicate const*, set<string>> collectInvariants(
38+
smtutil::Expression const& _proof,
39+
set<Predicate const*> const& _predicates,
40+
ModelCheckerInvariants const& _invariantsSetting
41+
)
3842
{
39-
set<string> targets{"interface_", "nondet_interface_"};
43+
set<string> targets;
44+
if (_invariantsSetting.has(InvariantType::Contract))
45+
targets.insert("interface_");
46+
if (_invariantsSetting.has(InvariantType::Reentrancy))
47+
targets.insert("nondet_interface_");
48+
4049
map<string, pair<smtutil::Expression, smtutil::Expression>> eqs;
4150
// Collect equalities where one of the sides is a predicate we're interested in.
4251
BreadthFirstSearch<smtutil::Expression const*>{{&_proof}}.run([&](auto&& _expr, auto&& _addChild) {
@@ -54,7 +63,7 @@ map<ASTNode const*, set<string>> collectInvariants(smtutil::Expression const& _p
5463
_addChild(&arg);
5564
});
5665

57-
map<ASTNode const*, set<string>> invariants;
66+
map<Predicate const*, set<string>> invariants;
5867
for (auto pred: _predicates)
5968
{
6069
auto predName = pred->functor().name;
@@ -69,7 +78,7 @@ map<ASTNode const*, set<string>> collectInvariants(smtutil::Expression const& _p
6978
auto r = substitute(invExpr, pred->expressionSubstitution(predExpr));
7079
// No point in reporting true/false as invariants.
7180
if (!ignore.count(r.name))
72-
invariants[pred->programNode()].insert(toSolidityStr(r));
81+
invariants[pred].insert(toSolidityStr(r));
7382
}
7483
return invariants;
7584
}

libsolidity/formal/Invariants.h

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

1919
#pragma once
2020

21+
#include <libsolidity/formal/ModelCheckerSettings.h>
2122
#include <libsolidity/formal/Predicate.h>
2223

2324
#include <map>
@@ -27,6 +28,10 @@
2728
namespace solidity::frontend::smt
2829
{
2930

30-
std::map<ASTNode const*, std::set<std::string>> collectInvariants(smtutil::Expression const& _proof, std::set<Predicate const*> const& _predicates);
31+
std::map<Predicate const*, std::set<std::string>> collectInvariants(
32+
smtutil::Expression const& _proof,
33+
std::set<Predicate const*> const& _predicates,
34+
ModelCheckerInvariants const& _invariantsSettings
35+
);
3136

3237
}

libsolidity/formal/ModelCheckerSettings.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,40 @@ using namespace std;
2525
using namespace solidity;
2626
using namespace solidity::frontend;
2727

28+
map<string, InvariantType> const ModelCheckerInvariants::validInvariants{
29+
{"contract", InvariantType::Contract},
30+
{"reentrancy", InvariantType::Reentrancy}
31+
};
32+
33+
std::optional<ModelCheckerInvariants> ModelCheckerInvariants::fromString(string const& _invs)
34+
{
35+
set<InvariantType> chosenInvs;
36+
if (_invs == "default")
37+
{
38+
// The default is that no invariants are reported.
39+
}
40+
else if (_invs == "all")
41+
for (auto&& v: validInvariants | ranges::views::values)
42+
chosenInvs.insert(v);
43+
else
44+
for (auto&& t: _invs | ranges::views::split(',') | ranges::to<vector<string>>())
45+
{
46+
if (!validInvariants.count(t))
47+
return {};
48+
chosenInvs.insert(validInvariants.at(t));
49+
}
50+
51+
return ModelCheckerInvariants{chosenInvs};
52+
}
53+
54+
bool ModelCheckerInvariants::setFromString(string const& _inv)
55+
{
56+
if (!validInvariants.count(_inv))
57+
return false;
58+
invariants.insert(validInvariants.at(_inv));
59+
return true;
60+
}
61+
2862
using TargetType = VerificationTargetType;
2963
map<string, TargetType> const ModelCheckerTargets::targetStrings{
3064
{"constantCondition", TargetType::ConstantCondition},

libsolidity/formal/ModelCheckerSettings.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,31 @@ struct ModelCheckerEngine
8787
bool operator==(ModelCheckerEngine const& _other) const noexcept { return bmc == _other.bmc && chc == _other.chc; }
8888
};
8989

90+
enum class InvariantType { Contract, Reentrancy };
91+
92+
struct ModelCheckerInvariants
93+
{
94+
/// Adds the default targets, that is, all except underflow and overflow.
95+
static ModelCheckerInvariants Default() { return *fromString("default"); }
96+
/// Adds all targets, including underflow and overflow.
97+
static ModelCheckerInvariants All() { return *fromString("all"); }
98+
99+
static std::optional<ModelCheckerInvariants> fromString(std::string const& _invs);
100+
101+
bool has(InvariantType _inv) const { return invariants.count(_inv); }
102+
103+
/// @returns true if the @p _target is valid,
104+
/// and false otherwise.
105+
bool setFromString(std::string const& _target);
106+
107+
static std::map<std::string, InvariantType> const validInvariants;
108+
109+
bool operator!=(ModelCheckerInvariants const& _other) const noexcept { return !(*this == _other); }
110+
bool operator==(ModelCheckerInvariants const& _other) const noexcept { return invariants == _other.invariants; }
111+
112+
std::set<InvariantType> invariants;
113+
};
114+
90115
enum class VerificationTargetType { ConstantCondition, Underflow, Overflow, UnderOverflow, DivByZero, Balance, Assert, PopEmptyArray, OutOfBounds };
91116

92117
struct ModelCheckerTargets
@@ -123,7 +148,7 @@ struct ModelCheckerSettings
123148
/// might prefer the precise encoding.
124149
bool divModNoSlacks = false;
125150
ModelCheckerEngine engine = ModelCheckerEngine::None();
126-
bool invariants = false;
151+
ModelCheckerInvariants invariants = ModelCheckerInvariants::Default();
127152
bool showUnproved = false;
128153
smtutil::SMTSolverChoice solvers = smtutil::SMTSolverChoice::All();
129154
ModelCheckerTargets targets = ModelCheckerTargets::Default();

libsolidity/formal/Predicate.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <libsolidity/formal/SymbolicVariables.h>
2222
#include <libsolidity/formal/SymbolicVariables.h>
2323

24+
#include <libsolidity/ast/AST.h>
25+
2426
#include <libsmtutil/Sorts.h>
2527

2628
#include <map>
@@ -214,4 +216,12 @@ class Predicate
214216
std::vector<ScopeOpener const*> const m_scopeStack;
215217
};
216218

219+
struct PredicateCompare
220+
{
221+
bool operator()(Predicate const* lhs, Predicate const* rhs) const
222+
{
223+
return lhs->programNode()->id() < rhs->programNode()->id();
224+
}
225+
};
226+
217227
}

libsolidity/interface/StandardCompiler.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ std::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
441441

442442
std::optional<Json::Value> checkModelCheckerSettingsKeys(Json::Value const& _input)
443443
{
444-
static set<string> keys{"contracts", "divModNoSlacks", "engine", "showUnproved", "solvers", "targets", "timeout"};
444+
static set<string> keys{"contracts", "divModNoSlacks", "engine", "invariants", "showUnproved", "solvers", "targets", "timeout"};
445445
return checkKeys(_input, keys, "modelChecker");
446446
}
447447

@@ -958,6 +958,27 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
958958
ret.modelCheckerSettings.engine = *engine;
959959
}
960960

961+
if (modelCheckerSettings.isMember("invariants"))
962+
{
963+
auto const& invariantsArray = modelCheckerSettings["invariants"];
964+
if (!invariantsArray.isArray())
965+
return formatFatalError("JSONError", "settings.modelChecker.invariants must be an array.");
966+
967+
ModelCheckerInvariants invariants;
968+
for (auto const& i: invariantsArray)
969+
{
970+
if (!i.isString())
971+
return formatFatalError("JSONError", "Every invariant type in settings.modelChecker.invariants must be a string.");
972+
if (!invariants.setFromString(i.asString()))
973+
return formatFatalError("JSONError", "Invalid model checker invariants requested.");
974+
}
975+
976+
if (invariants.invariants.empty())
977+
return formatFatalError("JSONError", "settings.modelChecker.invariants must be a non-empty array.");
978+
979+
ret.modelCheckerSettings.invariants = invariants;
980+
}
981+
961982
if (modelCheckerSettings.isMember("showUnproved"))
962983
{
963984
auto const& showUnproved = modelCheckerSettings["showUnproved"];

solc/CommandLineParser.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,10 @@ General Information)").c_str(),
746746
)
747747
(
748748
g_strModelCheckerInvariants.c_str(),
749+
po::value<string>()->value_name("default,all,contract,reentrancy")->default_value("default"),
749750
"Select whether to report inferred contract inductive invariants."
751+
"Multiple types of invariants can be selected at the same time, separated by a comma and no spaces."
752+
" By default no invariants are reported."
750753
)
751754
(
752755
g_strModelCheckerShowUnproved.c_str(),
@@ -1170,7 +1173,16 @@ bool CommandLineParser::processArgs()
11701173
}
11711174

11721175
if (m_args.count(g_strModelCheckerInvariants))
1173-
m_options.modelChecker.settings.invariants = true;
1176+
{
1177+
string invsStr = m_args[g_strModelCheckerInvariants].as<string>();
1178+
optional<ModelCheckerInvariants> invs = ModelCheckerInvariants::fromString(invsStr);
1179+
if (!invs)
1180+
{
1181+
serr() << "Invalid option for --" << g_strModelCheckerInvariants << ": " << invsStr << endl;
1182+
return false;
1183+
}
1184+
m_options.modelChecker.settings.invariants = *invs;
1185+
}
11741186

11751187
if (m_args.count(g_strModelCheckerShowUnproved))
11761188
m_options.modelChecker.settings.showUnproved = true;

test/libsolidity/SMTCheckerTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ SMTCheckerTest::SMTCheckerTest(string const& _filename): SyntaxTest(_filename, E
5959
if (m_modelCheckerSettings.solvers.none() || m_modelCheckerSettings.engine.none())
6060
m_shouldRun = false;
6161

62-
m_modelCheckerSettings.invariants = true;
62+
m_modelCheckerSettings.invariants = ModelCheckerInvariants::All();
6363

6464
auto const& ignoreCex = m_reader.stringSetting("SMTIgnoreCex", "no");
6565
if (ignoreCex == "no")

0 commit comments

Comments
 (0)