/src/solidity/libsolidity/formal/ModelCheckerSettings.h
Line | Count | Source |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | |
19 | | #pragma once |
20 | | |
21 | | #include <libsmtutil/SolverInterface.h> |
22 | | |
23 | | #include <optional> |
24 | | #include <set> |
25 | | |
26 | | namespace solidity::frontend |
27 | | { |
28 | | |
29 | | struct ModelCheckerContracts |
30 | | { |
31 | | /// By default all contracts are analyzed. |
32 | 50.4k | static ModelCheckerContracts Default() { return {}; } |
33 | | |
34 | | /// Parses a string of the form <path>:<contract>,<path>:contract,... |
35 | | /// and returns nullopt if a path or contract name is empty. |
36 | | static std::optional<ModelCheckerContracts> fromString(std::string const& _contracts); |
37 | | |
38 | | /// @returns true if all contracts should be analyzed. |
39 | 41.6k | bool isDefault() const { return contracts.empty(); } |
40 | | |
41 | 0 | bool has(std::string const& _source) const { return contracts.count(_source); } |
42 | | bool has(std::string const& _source, std::string const& _contract) const |
43 | 0 | { |
44 | 0 | return has(_source) && contracts.at(_source).count(_contract); |
45 | 0 | } |
46 | | |
47 | 0 | bool operator!=(ModelCheckerContracts const& _other) const noexcept { return !(*this == _other); } |
48 | 0 | bool operator==(ModelCheckerContracts const& _other) const noexcept { return contracts == _other.contracts; } |
49 | | |
50 | | /// Represents which contracts should be analyzed by the SMTChecker |
51 | | /// as the most derived. |
52 | | /// The key is the source file. If the map is empty, all sources must be analyzed. |
53 | | /// For each source, contracts[source] represents the contracts in that source |
54 | | /// that should be analyzed. |
55 | | /// If the set of contracts is empty, all contracts in that source should be analyzed. |
56 | | std::map<std::string, std::set<std::string>> contracts; |
57 | | }; |
58 | | |
59 | | struct ModelCheckerEngine |
60 | | { |
61 | | bool bmc = false; |
62 | | bool chc = false; |
63 | | |
64 | 36.7k | static constexpr ModelCheckerEngine All() { return {true, true}; } |
65 | 0 | static constexpr ModelCheckerEngine BMC() { return {true, false}; } |
66 | 0 | static constexpr ModelCheckerEngine CHC() { return {false, true}; } |
67 | 25.5k | static constexpr ModelCheckerEngine None() { return {false, false}; } |
68 | | |
69 | 14.1k | bool none() const { return !any(); } |
70 | 26.6k | bool any() const { return bmc || chc; } |
71 | 0 | bool all() const { return bmc && chc; } |
72 | | |
73 | | static std::optional<ModelCheckerEngine> fromString(std::string const& _engine) |
74 | 0 | { |
75 | 0 | static std::map<std::string, ModelCheckerEngine> engineMap{ |
76 | 0 | {"all", All()}, |
77 | 0 | {"bmc", BMC()}, |
78 | 0 | {"chc", CHC()}, |
79 | 0 | {"none", None()} |
80 | 0 | }; |
81 | 0 | if (engineMap.count(_engine)) |
82 | 0 | return engineMap.at(_engine); |
83 | 0 | return {}; |
84 | 0 | } |
85 | | |
86 | 0 | bool operator!=(ModelCheckerEngine const& _other) const noexcept { return !(*this == _other); } |
87 | 0 | bool operator==(ModelCheckerEngine const& _other) const noexcept { return bmc == _other.bmc && chc == _other.chc; } |
88 | | }; |
89 | | |
90 | | enum class InvariantType { Contract, Reentrancy }; |
91 | | |
92 | | struct ModelCheckerInvariants |
93 | | { |
94 | | /// Adds the default targets, that is, all except underflow and overflow. |
95 | 25.5k | static ModelCheckerInvariants Default() { return *fromString("default"); } |
96 | | /// Adds all targets, including underflow and overflow. |
97 | 24.8k | static ModelCheckerInvariants All() { return *fromString("all"); } |
98 | 0 | static ModelCheckerInvariants None() { return {{}}; } |
99 | | |
100 | | static std::optional<ModelCheckerInvariants> fromString(std::string const& _invs); |
101 | | |
102 | 0 | bool has(InvariantType _inv) const { return invariants.count(_inv); } |
103 | | |
104 | | /// @returns true if the @p _target is valid, |
105 | | /// and false otherwise. |
106 | | bool setFromString(std::string const& _target); |
107 | | |
108 | | static std::map<std::string, InvariantType> const validInvariants; |
109 | | |
110 | 0 | bool operator!=(ModelCheckerInvariants const& _other) const noexcept { return !(*this == _other); } |
111 | 0 | bool operator==(ModelCheckerInvariants const& _other) const noexcept { return invariants == _other.invariants; } |
112 | | |
113 | | std::set<InvariantType> invariants; |
114 | | }; |
115 | | |
116 | | enum class VerificationTargetType { ConstantCondition, Underflow, Overflow, DivByZero, Balance, Assert, PopEmptyArray, OutOfBounds }; |
117 | | |
118 | | struct ModelCheckerTargets |
119 | | { |
120 | | /// Adds the default targets, that is, all except underflow and overflow. |
121 | 50.4k | static ModelCheckerTargets Default() { return *fromString("default"); } |
122 | | /// Adds all targets, including underflow and overflow. |
123 | 0 | static ModelCheckerTargets All() { return *fromString("all"); } |
124 | | |
125 | | static std::optional<ModelCheckerTargets> fromString(std::string const& _targets); |
126 | | |
127 | 37.5k | bool has(VerificationTargetType _type) const { return targets.count(_type); } |
128 | | |
129 | | /// @returns true if the @p _target is valid, |
130 | | /// and false otherwise. |
131 | | bool setFromString(std::string const& _target); |
132 | | |
133 | | static std::map<std::string, VerificationTargetType> const targetStrings; |
134 | | |
135 | | static std::map<VerificationTargetType, std::string> const targetTypeToString; |
136 | | |
137 | 0 | bool operator!=(ModelCheckerTargets const& _other) const noexcept { return !(*this == _other); } |
138 | 0 | bool operator==(ModelCheckerTargets const& _other) const noexcept { return targets == _other.targets; } |
139 | | |
140 | | std::set<VerificationTargetType> targets; |
141 | | }; |
142 | | |
143 | | struct ModelCheckerExtCalls |
144 | | { |
145 | | enum class Mode |
146 | | { |
147 | | UNTRUSTED, |
148 | | TRUSTED |
149 | | }; |
150 | | |
151 | | Mode mode = Mode::UNTRUSTED; |
152 | | |
153 | | static std::optional<ModelCheckerExtCalls> fromString(std::string const& _mode); |
154 | | |
155 | 69.3k | bool isTrusted() const { return mode == Mode::TRUSTED; } |
156 | | }; |
157 | | |
158 | | struct ModelCheckerSettings |
159 | | { |
160 | | std::optional<unsigned> bmcLoopIterations; |
161 | | ModelCheckerContracts contracts = ModelCheckerContracts::Default(); |
162 | | /// Currently division and modulo are replaced by multiplication with slack vars, such that |
163 | | /// a / b <=> a = b * k + m |
164 | | /// where k and m are slack variables. |
165 | | /// This is the default because Spacer prefers that over precise / and mod. |
166 | | /// This option allows disabling this mechanism since other solvers |
167 | | /// might prefer the precise encoding. |
168 | | bool divModNoSlacks = false; |
169 | | ModelCheckerEngine engine = ModelCheckerEngine::None(); |
170 | | ModelCheckerExtCalls externalCalls = {}; |
171 | | ModelCheckerInvariants invariants = ModelCheckerInvariants::Default(); |
172 | | bool printQuery = false; |
173 | | bool showProvedSafe = false; |
174 | | bool showUnproved = false; |
175 | | bool showUnsupported = false; |
176 | | smtutil::SMTSolverChoice solvers = smtutil::SMTSolverChoice::Z3(); |
177 | | ModelCheckerTargets targets = ModelCheckerTargets::Default(); |
178 | | std::optional<unsigned> timeout; // in milliseconds |
179 | | |
180 | 0 | bool operator!=(ModelCheckerSettings const& _other) const noexcept { return !(*this == _other); } |
181 | | bool operator==(ModelCheckerSettings const& _other) const noexcept |
182 | 0 | { |
183 | 0 | return |
184 | 0 | bmcLoopIterations == _other.bmcLoopIterations && |
185 | 0 | contracts == _other.contracts && |
186 | 0 | divModNoSlacks == _other.divModNoSlacks && |
187 | 0 | engine == _other.engine && |
188 | 0 | externalCalls.mode == _other.externalCalls.mode && |
189 | 0 | invariants == _other.invariants && |
190 | 0 | printQuery == _other.printQuery && |
191 | 0 | showProvedSafe == _other.showProvedSafe && |
192 | 0 | showUnproved == _other.showUnproved && |
193 | 0 | showUnsupported == _other.showUnsupported && |
194 | 0 | solvers == _other.solvers && |
195 | 0 | targets == _other.targets && |
196 | 0 | timeout == _other.timeout; |
197 | 0 | } |
198 | | }; |
199 | | |
200 | | } |