Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/formal/Predicate.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
22
#include <libsolidity/ast/ASTForward.h>
23
#include <libsolidity/ast/Types.h>
24
25
#include <libsmtutil/SolverInterface.h>
26
#include <libsmtutil/Sorts.h>
27
28
#include <map>
29
#include <optional>
30
#include <vector>
31
32
namespace solidity::langutil
33
{
34
class CharStreamProvider;
35
}
36
37
namespace solidity::frontend
38
{
39
40
namespace smt
41
{
42
class EncodingContext;
43
}
44
45
enum class PredicateType
46
{
47
  Interface,
48
  NondetInterface,
49
  ConstructorSummary,
50
  FunctionSummary,
51
  FunctionBlock,
52
  FunctionErrorBlock,
53
  InternalCall,
54
  ExternalCallTrusted,
55
  ExternalCallUntrusted,
56
  Error,
57
  Custom
58
};
59
60
/**
61
 * Represents a predicate used by the CHC engine.
62
 */
63
class Predicate
64
{
65
public:
66
  static Predicate const* create(
67
    smtutil::SortPointer _sort,
68
    std::string _name,
69
    PredicateType _type,
70
    smt::EncodingContext& _context,
71
    ASTNode const* _node = nullptr,
72
    ContractDefinition const* _contractContext = nullptr,
73
    std::vector<ScopeOpener const*> _scopeStack = {}
74
  );
75
76
  Predicate(
77
    std::string _name,
78
    smtutil::SortPointer _sort,
79
    PredicateType _type,
80
    bool _bytesConcatFunctionInContext,
81
    ASTNode const* _node = nullptr,
82
    ContractDefinition const* _contractContext = nullptr,
83
    std::vector<ScopeOpener const*> _scopeStack = {}
84
  );
85
86
  /// Predicate should not be copiable.
87
  Predicate(Predicate const&) = delete;
88
  Predicate& operator=(Predicate const&) = delete;
89
90
  /// @returns the Predicate associated with _name.
91
  static Predicate const* predicate(std::string const& _name);
92
93
  /// Resets all the allocated predicates.
94
  static void reset();
95
96
  /// @returns a function application of the predicate over _args.
97
  smtutil::Expression operator()(std::vector<smtutil::Expression> const& _args) const;
98
99
  /// @returns the function declaration of the predicate.
100
  smtutil::Expression const& functor() const;
101
102
  /// @returns the program node this predicate represents.
103
  ASTNode const* programNode() const;
104
105
  /// @returns the ContractDefinition of the most derived contract
106
  /// being analyzed.
107
  ContractDefinition const* contextContract() const;
108
109
  /// @returns the ContractDefinition that this predicate represents
110
  /// or nullptr otherwise.
111
  ContractDefinition const* programContract() const;
112
113
  /// @returns the FunctionDefinition that this predicate represents
114
  /// or nullptr otherwise.
115
  FunctionDefinition const* programFunction() const;
116
117
  /// @returns the FunctionCall that this predicate represents
118
  /// or nullptr otherwise.
119
  FunctionCall const* programFunctionCall() const;
120
121
  /// @returns the VariableDeclaration that this predicate represents
122
  /// or nullptr otherwise.
123
  VariableDeclaration const* programVariable() const;
124
125
  /// @returns the program state variables in the scope of this predicate.
126
  std::optional<std::vector<VariableDeclaration const*>> stateVariables() const;
127
128
  /// @returns true if this predicate represents a summary.
129
  bool isSummary() const;
130
131
  /// @returns true if this predicate represents a function summary.
132
  bool isFunctionSummary() const;
133
134
  /// @returns true if this predicate represents a function block.
135
  bool isFunctionBlock() const;
136
137
  /// @returns true if this predicate represents a function error block.
138
  bool isFunctionErrorBlock() const;
139
140
  /// @returns true if this predicate represents an internal function call.
141
  bool isInternalCall() const;
142
143
  /// @returns true if this predicate represents a trusted external function call.
144
  bool isExternalCallTrusted() const;
145
146
  /// @returns true if this predicate represents an untrusted external function call.
147
  bool isExternalCallUntrusted() const;
148
149
  /// @returns true if this predicate represents a constructor summary.
150
  bool isConstructorSummary() const;
151
152
  /// @returns true if this predicate represents an interface.
153
  bool isInterface() const;
154
155
  /// @returns true if this predicate represents a nondeterministic interface.
156
  bool isNondetInterface() const;
157
158
366k
  PredicateType type() const { return m_type; }
159
160
  /// @returns a formatted string representing a call to this predicate
161
  /// with _args.
162
  std::string formatSummaryCall(
163
    std::vector<smtutil::Expression> const& _args,
164
    langutil::CharStreamProvider const& _charStreamProvider,
165
    bool _appendTxVars = false
166
  ) const;
167
168
  /// @returns the values of the state variables from _args at the point
169
  /// where this summary was reached.
170
  std::vector<std::optional<std::string>> summaryStateValues(std::vector<smtutil::Expression> const& _args) const;
171
172
  /// @returns the values of the function input variables from _args at the point
173
  /// where this summary was reached.
174
  std::vector<std::optional<std::string>> summaryPostInputValues(std::vector<smtutil::Expression> const& _args) const;
175
176
  /// @returns the values of the function output variables from _args at the point
177
  /// where this summary was reached.
178
  std::vector<std::optional<std::string>> summaryPostOutputValues(std::vector<smtutil::Expression> const& _args) const;
179
180
  /// @returns the values of the local variables used by this predicate.
181
  std::pair<std::vector<std::optional<std::string>>, std::vector<VariableDeclaration const*>> localVariableValues(std::vector<smtutil::Expression> const& _args) const;
182
183
  /// @returns a substitution map from the predicate arguments @p _predArgs
184
  /// to a Solidity-like expression.
185
  std::map<std::string, std::string> expressionSubstitution(std::vector<std::string> const& _predArgs) const;
186
187
private:
188
  /// Recursively fills _array from _expr.
189
  /// _expr should have the form `store(store(...(const_array(x_0), i_0, e_0), i_m, e_m), i_k, e_k)`.
190
  /// @returns true if the construction worked,
191
  /// and false if at least one element could not be built.
192
  bool fillArray(smtutil::Expression const& _expr, std::vector<std::string>& _array, ArrayType const& _type) const;
193
194
  std::map<std::string, std::optional<std::string>> readTxVars(smtutil::Expression const& _tx) const;
195
196
  /// @returns index at which transaction values start in args list
197
0
  size_t txValuesIndex() const { return m_bytesConcatFunctionInContext ? 5 : 4; }
198
  /// @returns index at which function arguments start in args list
199
0
  size_t firstArgIndex() const { return m_bytesConcatFunctionInContext ? 7 : 6; }
200
  /// @returns index at which state variables values start in args list
201
0
  size_t firstStateVarIndex() const { return m_bytesConcatFunctionInContext ? 8 : 7; }
202
203
  smtutil::Expression m_functor;
204
205
  /// The type of this predicate.
206
  PredicateType m_type;
207
208
  /// The ASTNode that this predicate represents.
209
  /// nullptr if this predicate is not associated with a specific program AST node.
210
  ASTNode const* m_node = nullptr;
211
212
  /// The ContractDefinition that contains this predicate.
213
  /// nullptr if this predicate is not associated with a specific contract.
214
  /// This is unfortunately necessary because of virtual resolution for
215
  /// function nodes.
216
  ContractDefinition const* m_contractContext = nullptr;
217
218
  /// Maps the name of the predicate to the actual Predicate.
219
  /// Used in counterexample generation.
220
  static std::map<std::string, Predicate> m_predicates;
221
222
  /// The scope stack when the predicate was created.
223
  /// Used to identify the subset of variables in scope.
224
  std::vector<ScopeOpener const*> const m_scopeStack;
225
226
  /// True iff there is a bytes concat function in contract scope
227
  bool m_bytesConcatFunctionInContext;
228
};
229
230
struct PredicateCompare
231
{
232
  bool operator()(Predicate const* lhs, Predicate const* rhs) const
233
0
  {
234
    // We cannot use m_node->id() because different predicates may
235
    // represent the same program node.
236
    // We use the symbolic name since it is unique per predicate and
237
    // the order does not really matter.
238
0
    return lhs->functor().name < rhs->functor().name;
239
0
  }
240
};
241
242
}