Coverage Report

Created: 2026-06-30 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}