/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 | | } |