/src/solidity/libsolidity/formal/SMTEncoder.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 | | * Encodes Solidity into SMT expressions without creating |
20 | | * any verification targets. |
21 | | * Also implements the SSA scheme for branches. |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | |
27 | | #include <libsolidity/formal/EncodingContext.h> |
28 | | #include <libsolidity/formal/ModelCheckerSettings.h> |
29 | | #include <libsolidity/formal/SymbolicVariables.h> |
30 | | |
31 | | #include <libsolidity/ast/AST.h> |
32 | | #include <libsolidity/ast/ASTVisitor.h> |
33 | | #include <libsolidity/interface/ReadFile.h> |
34 | | #include <liblangutil/UniqueErrorReporter.h> |
35 | | |
36 | | #include <string> |
37 | | #include <unordered_map> |
38 | | #include <vector> |
39 | | #include <utility> |
40 | | |
41 | | namespace solidity::langutil |
42 | | { |
43 | | class ErrorReporter; |
44 | | struct SourceLocation; |
45 | | class CharStreamProvider; |
46 | | } |
47 | | |
48 | | namespace solidity::frontend |
49 | | { |
50 | | |
51 | | class SMTEncoder: public ASTConstVisitor |
52 | | { |
53 | | public: |
54 | | SMTEncoder( |
55 | | smt::EncodingContext& _context, |
56 | | ModelCheckerSettings _settings, |
57 | | langutil::UniqueErrorReporter& _errorReporter, |
58 | | langutil::UniqueErrorReporter& _unsupportedErrorReporter, |
59 | | langutil::ErrorReporter& _provedSafeReporter, |
60 | | langutil::CharStreamProvider const& _charStreamProvider |
61 | | ); |
62 | | |
63 | | /// @returns the leftmost identifier in a multi-d IndexAccess. |
64 | | static Expression const* leftmostBase(IndexAccess const& _indexAccess); |
65 | | |
66 | | /// @returns the key type in _type. |
67 | | /// _type must allow IndexAccess, that is, |
68 | | /// it must be either ArrayType or MappingType |
69 | | static Type const* keyType(Type const* _type); |
70 | | |
71 | | /// @returns the innermost element in a chain of 1-tuples if applicable, |
72 | | /// otherwise _expr. |
73 | | static Expression const& innermostTuple(Expression const& _expr); |
74 | | |
75 | | /// @returns the underlying type if _type is UserDefinedValueType, |
76 | | /// and _type otherwise. |
77 | | static Type const* underlyingType(Type const* _type); |
78 | | |
79 | | static TypePointers replaceUserTypes(TypePointers const& _types); |
80 | | |
81 | | /// @returns {_funCall.expression(), nullptr} if function call option values are not given, and |
82 | | /// {_funCall.expression().expression(), _funCall.expression()} if they are. |
83 | | static std::pair<Expression const*, FunctionCallOptions const*> functionCallExpression(FunctionCall const& _funCall); |
84 | | |
85 | | /// @returns the expression after stripping redundant syntactic sugar. |
86 | | /// Currently supports stripping: |
87 | | /// 1. 1-tuple; i.e. ((x)) -> x |
88 | | /// 2. Explicit cast from string to bytes; i.e. bytes(s) -> s; for s of type string |
89 | | static Expression const* cleanExpression(Expression const& _expr); |
90 | | |
91 | | /// @returns the FunctionDefinition of a FunctionCall |
92 | | /// if possible or nullptr. |
93 | | /// @param _scopeContract is the contract that contains the function currently being |
94 | | /// analyzed, if applicable. |
95 | | /// @param _contextContract is the most derived contract currently being analyzed. |
96 | | /// The difference between the two parameters appears in the case of inheritance. |
97 | | /// Let A and B be two contracts so that B derives from A, and A defines a function `f` |
98 | | /// that `B` does not override. Function `f` is visited twice: |
99 | | /// - Once when A is the most derived contract, where both _scopeContract and _contextContract are A. |
100 | | /// - Once when B is the most derived contract, where _scopeContract is A and _contextContract is B. |
101 | | static FunctionDefinition const* functionCallToDefinition( |
102 | | FunctionCall const& _funCall, |
103 | | ContractDefinition const* _scopeContract, |
104 | | ContractDefinition const* _contextContract |
105 | | ); |
106 | | |
107 | | static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(ContractDefinition const& _contract); |
108 | | static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(FunctionDefinition const& _function); |
109 | | |
110 | | static std::vector<VariableDeclaration const*> localVariablesIncludingModifiers(FunctionDefinition const& _function, ContractDefinition const* _contract); |
111 | | static std::vector<VariableDeclaration const*> modifiersVariables(FunctionDefinition const& _function, ContractDefinition const* _contract); |
112 | | static std::vector<VariableDeclaration const*> tryCatchVariables(FunctionDefinition const& _function); |
113 | | |
114 | | /// @returns the ModifierDefinition of a ModifierInvocation if possible, or nullptr. |
115 | | static ModifierDefinition const* resolveModifierInvocation(ModifierInvocation const& _invocation, ContractDefinition const* _contract); |
116 | | |
117 | | /// @returns the arguments for each base constructor call in the hierarchy of @a _contract. |
118 | | std::map<ContractDefinition const*, std::vector<ASTPointer<frontend::Expression>>> baseArguments(ContractDefinition const& _contract); |
119 | | |
120 | | /// @returns a valid RationalNumberType pointer if _expr has type |
121 | | /// RationalNumberType or can be const evaluated, and nullptr otherwise. |
122 | | static RationalNumberType const* isConstant(Expression const& _expr); |
123 | | |
124 | | static std::set<FunctionCall const*, ASTCompareByID<FunctionCall>> collectABICalls(ASTNode const* _node); |
125 | | static std::set<FunctionCall const*, ASTCompareByID<FunctionCall>> collectBytesConcatCalls(ASTNode const* _node); |
126 | | |
127 | | /// @returns all the sources that @param _source depends on, |
128 | | /// including itself. |
129 | | static std::set<SourceUnit const*, ASTNode::CompareByID> sourceDependencies(SourceUnit const& _source); |
130 | | |
131 | | protected: |
132 | | struct TransientDataLocationChecker: ASTConstVisitor |
133 | | { |
134 | 35.4k | TransientDataLocationChecker(ContractDefinition const& _contract) { _contract.accept(*this); } |
135 | | |
136 | | void endVisit(VariableDeclaration const& _var) |
137 | 66.4k | { |
138 | 66.4k | solUnimplementedAssert( |
139 | 66.4k | _var.referenceLocation() != VariableDeclaration::Location::Transient, |
140 | 66.4k | "Transient storage variables are not supported." |
141 | 66.4k | ); |
142 | 66.4k | } |
143 | | }; |
144 | | |
145 | | void resetSourceAnalysis(); |
146 | | |
147 | | // TODO: Check that we do not have concurrent reads and writes to a variable, |
148 | | // because the order of expression evaluation is undefined |
149 | | // TODO: or just force a certain order, but people might have a different idea about that. |
150 | | |
151 | | bool visit(ImportDirective const& _node) override; |
152 | | bool visit(ContractDefinition const& _node) override; |
153 | | void endVisit(ContractDefinition const& _node) override; |
154 | | void endVisit(VariableDeclaration const& _node) override; |
155 | | bool visit(ModifierDefinition const& _node) override; |
156 | | bool visit(FunctionDefinition const& _node) override; |
157 | | void endVisit(FunctionDefinition const& _node) override; |
158 | | bool visit(Block const& _node) override; |
159 | | void endVisit(Block const& _node) override; |
160 | | bool visit(PlaceholderStatement const& _node) override; |
161 | 0 | bool visit(IfStatement const&) override { return false; } |
162 | 0 | bool visit(WhileStatement const&) override { return false; } |
163 | 0 | bool visit(ForStatement const&) override { return false; } |
164 | 797 | void endVisit(ForStatement const&) override {} |
165 | | void endVisit(VariableDeclarationStatement const& _node) override; |
166 | | bool visit(Assignment const& _node) override; |
167 | | void endVisit(Assignment const& _node) override; |
168 | | void endVisit(TupleExpression const& _node) override; |
169 | | bool visit(UnaryOperation const& _node) override; |
170 | | void endVisit(UnaryOperation const& _node) override; |
171 | | bool visit(BinaryOperation const& _node) override; |
172 | | void endVisit(BinaryOperation const& _node) override; |
173 | | bool visit(Conditional const& _node) override; |
174 | | bool visit(FunctionCall const& _node) override; |
175 | | void endVisit(FunctionCall const& _node) override; |
176 | | bool visit(ModifierInvocation const& _node) override; |
177 | | void endVisit(Identifier const& _node) override; |
178 | | void endVisit(ElementaryTypeNameExpression const& _node) override; |
179 | | void endVisit(Literal const& _node) override; |
180 | | void endVisit(Return const& _node) override; |
181 | | bool visit(MemberAccess const& _node) override; |
182 | | void endVisit(IndexAccess const& _node) override; |
183 | | void endVisit(IndexRangeAccess const& _node) override; |
184 | | bool visit(InlineAssembly const& _node) override; |
185 | 111 | bool visit(Break const&) override { return false; } |
186 | 96 | void endVisit(Break const&) override {} |
187 | 121 | bool visit(Continue const&) override { return false; } |
188 | 96 | void endVisit(Continue const&) override {} |
189 | 630 | bool visit(TryCatchClause const&) override { return true; } |
190 | 322 | void endVisit(TryCatchClause const&) override {} |
191 | 0 | bool visit(TryStatement const&) override { return false; } |
192 | | |
193 | | virtual void pushInlineFrame(CallableDeclaration const&); |
194 | | virtual void popInlineFrame(CallableDeclaration const&); |
195 | | |
196 | | /// Do not visit subtree if node is a RationalNumber. |
197 | | /// Symbolic _expr is the rational literal. |
198 | | bool shortcutRationalNumber(Expression const& _expr); |
199 | | void arithmeticOperation(BinaryOperation const& _op); |
200 | | /// @returns _op(_left, _right) with and without modular arithmetic. |
201 | | /// Used by the function above, compound assignments and |
202 | | /// unary increment/decrement. |
203 | | virtual std::pair<smtutil::Expression, smtutil::Expression> arithmeticOperation( |
204 | | Token _op, |
205 | | smtutil::Expression const& _left, |
206 | | smtutil::Expression const& _right, |
207 | | Type const* _commonType, |
208 | | Expression const& _expression |
209 | | ); |
210 | | |
211 | | smtutil::Expression bitwiseOperation( |
212 | | Token _op, |
213 | | smtutil::Expression const& _left, |
214 | | smtutil::Expression const& _right, |
215 | | Type const* _commonType |
216 | | ); |
217 | | |
218 | | void compareOperation(BinaryOperation const& _op); |
219 | | void booleanOperation(BinaryOperation const& _op); |
220 | | void bitwiseOperation(BinaryOperation const& _op); |
221 | | void bitwiseNotOperation(UnaryOperation const& _op); |
222 | | |
223 | | void initContract(ContractDefinition const& _contract); |
224 | | void initFunction(FunctionDefinition const& _function); |
225 | | void visitAssert(FunctionCall const& _funCall); |
226 | | void visitRequire(FunctionCall const& _funCall); |
227 | | void visitABIFunction(FunctionCall const& _funCall); |
228 | | void visitBytesConcat(FunctionCall const& _funCall); |
229 | | void visitCryptoFunction(FunctionCall const& _funCall); |
230 | | void visitGasLeft(FunctionCall const& _funCall); |
231 | | void visitBlobHash(FunctionCall const& _funCall); |
232 | | virtual void visitAddMulMod(FunctionCall const& _funCall); |
233 | | void visitWrapUnwrap(FunctionCall const& _funCall); |
234 | | void visitObjectCreation(FunctionCall const& _funCall); |
235 | | void visitTypeConversion(FunctionCall const& _funCall); |
236 | | void visitStructConstructorCall(FunctionCall const& _funCall); |
237 | | void visitFunctionIdentifier(Identifier const& _identifier); |
238 | | virtual void visitPublicGetter(FunctionCall const& _funCall); |
239 | | |
240 | | /// @returns true if symbolic representation of @param _contract is required for verification |
241 | | bool shouldEncode(ContractDefinition const& _contract) const; |
242 | | /// @returns true if the verification targets of @param _contract are actually selected for verification |
243 | | bool shouldAnalyzeVerificationTargetsFor(ContractDefinition const& _contract) const; |
244 | | /// @returns true if we should descend into @param _source to look for contracts that should be verified |
245 | | bool shouldAnalyzeVerificationTargetsFor(SourceUnit const& _source) const; |
246 | | |
247 | | /// @returns the state variable returned by a public getter if |
248 | | /// @a _expr is a call to a public getter, |
249 | | /// otherwise nullptr. |
250 | | VariableDeclaration const* publicGetter(Expression const& _expr) const; |
251 | | |
252 | | smtutil::Expression contractAddressValue(FunctionCall const& _f); |
253 | | |
254 | | /// Encodes a modifier or function body according to the modifier |
255 | | /// visit depth. |
256 | | void visitFunctionOrModifier(); |
257 | | |
258 | | /// Inlines a modifier or base constructor call. |
259 | | void inlineModifierInvocation(ModifierInvocation const* _invocation, CallableDeclaration const* _definition); |
260 | | |
261 | | /// Inlines the constructor hierarchy into a single constructor. |
262 | | void inlineConstructorHierarchy(ContractDefinition const& _contract); |
263 | | |
264 | | /// Defines a new global variable or function. |
265 | | void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); |
266 | | |
267 | | /// Handles the side effects of assignment |
268 | | /// to variable of some SMT array type |
269 | | /// while aliasing is not supported. |
270 | | void arrayAssignment(); |
271 | | /// Handles assignments to index or member access. |
272 | | void indexOrMemberAssignment(Expression const& _expr, smtutil::Expression const& _rightHandSide); |
273 | | |
274 | | void arrayPush(FunctionCall const& _funCall); |
275 | | void arrayPop(FunctionCall const& _funCall); |
276 | | /// Allows BMC and CHC to create verification targets for popping |
277 | | /// an empty array. |
278 | 263 | virtual void makeArrayPopVerificationTarget(FunctionCall const&) {} |
279 | | /// Allows BMC and CHC to create verification targets for out of bounds access. |
280 | 17.2k | virtual void makeOutOfBoundsVerificationTarget(IndexAccess const&) {} |
281 | | |
282 | | void addArrayLiteralAssertions( |
283 | | smt::SymbolicArrayVariable& _symArray, |
284 | | std::vector<smtutil::Expression> const& _elementValues |
285 | | ); |
286 | | |
287 | | void bytesToFixedBytesAssertions( |
288 | | smt::SymbolicArrayVariable& _symArray, |
289 | | Expression const& _fixedBytes |
290 | | ); |
291 | | |
292 | | /// @returns a pair of expressions representing _left / _right and _left mod _right, respectively. |
293 | | /// Uses slack variables and additional constraints to express the results using only operations |
294 | | /// more friendly to the SMT solver (multiplication, addition, subtraction and comparison). |
295 | | std::pair<smtutil::Expression, smtutil::Expression> divModWithSlacks( |
296 | | smtutil::Expression _left, |
297 | | smtutil::Expression _right, |
298 | | IntegerType const& _type |
299 | | ); |
300 | | |
301 | | /// Handles the actual assertion of the new value to the encoding context. |
302 | | /// Other assignment methods should use this one in the end. |
303 | | virtual void assignment(smt::SymbolicVariable& _symVar, smtutil::Expression const& _value); |
304 | | |
305 | | void assignment(VariableDeclaration const& _variable, Expression const& _value); |
306 | | /// Handles assignments to variables of different types. |
307 | | void assignment(VariableDeclaration const& _variable, smtutil::Expression const& _value); |
308 | | /// Handles assignments between generic expressions. |
309 | | /// Will also be used for assignments of tuple components. |
310 | | void assignment(Expression const& _left, smtutil::Expression const& _right); |
311 | | void assignment( |
312 | | Expression const& _left, |
313 | | smtutil::Expression const& _right, |
314 | | Type const* _type |
315 | | ); |
316 | | /// Handle assignments between tuples. |
317 | | void tupleAssignment(Expression const& _left, Expression const& _right); |
318 | | /// Computes the right hand side of a compound assignment. |
319 | | smtutil::Expression compoundAssignment(Assignment const& _assignment); |
320 | | /// Handles assignment of an expression to a tuple of variables. |
321 | | void expressionToTupleAssignment(std::vector<std::shared_ptr<VariableDeclaration>> const& _variables, Expression const& _rhs); |
322 | | |
323 | | /// Maps a variable to an SSA index. |
324 | | using VariableIndices = std::unordered_map<VariableDeclaration const*, unsigned>; |
325 | | |
326 | | /// Visits the branch given by the statement, pushes and pops the current path conditions. |
327 | | /// @param _condition if present, asserts that this condition is true within the branch. |
328 | | /// @returns the variable indices after visiting the branch and the expression representing |
329 | | /// the path condition at the end of the branch. |
330 | | std::pair<VariableIndices, smtutil::Expression> visitBranch(ASTNode const* _statement, smtutil::Expression const* _condition = nullptr); |
331 | | std::pair<VariableIndices, smtutil::Expression> visitBranch(ASTNode const* _statement, smtutil::Expression _condition); |
332 | | |
333 | | using CallStackEntry = std::pair<CallableDeclaration const*, ASTNode const*>; |
334 | | |
335 | | void createStateVariables(ContractDefinition const& _contract); |
336 | | void initializeStateVariables(ContractDefinition const& _contract); |
337 | | void createLocalVariables(FunctionDefinition const& _function); |
338 | | void initializeLocalVariables(FunctionDefinition const& _function); |
339 | | void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector<smtutil::Expression> const& _callArgs); |
340 | | void resetStateVariables(); |
341 | | void resetStorageVariables(); |
342 | | void resetMemoryVariables(); |
343 | | void resetBalances(); |
344 | | /// Resets all references/pointers that have the same type or have |
345 | | /// a subexpression of the same type as _varDecl. |
346 | | void resetReferences(VariableDeclaration const& _varDecl); |
347 | | /// Resets all references/pointers that have type _type. |
348 | | void resetReferences(Type const* _type); |
349 | | /// @returns the type without storage pointer information if it has it. |
350 | | Type const* typeWithoutPointer(Type const* _type); |
351 | | /// @returns whether _a or a subtype of _a is the same as _b. |
352 | | bool sameTypeOrSubtype(Type const* _a, Type const* _b); |
353 | | |
354 | | bool isSupportedType(Type const& _type) const; |
355 | | |
356 | | /// Given the state of the symbolic variables at the end of two different branches, |
357 | | /// create a merged state using the given branch condition. |
358 | | void mergeVariables(smtutil::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse); |
359 | | /// Tries to create an uninitialized variable and returns true on success. |
360 | | bool createVariable(VariableDeclaration const& _varDecl); |
361 | | |
362 | | /// @returns an expression denoting the value of the variable declared in @a _decl |
363 | | /// at the current point. |
364 | | smtutil::Expression currentValue(VariableDeclaration const& _decl) const; |
365 | | /// @returns an expression denoting the value of the variable declared in @a _decl |
366 | | /// at the given index. Does not ensure that this index exists. |
367 | | smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index) const; |
368 | | /// Returns the expression corresponding to the AST node. |
369 | | /// If _targetType is not null apply conversion. |
370 | | /// Throws if the expression does not exist. |
371 | | smtutil::Expression expr(Expression const& _e, Type const* _targetType = nullptr); |
372 | | /// Creates the expression (value can be arbitrary) |
373 | | void createExpr(Expression const& _e); |
374 | | /// Creates the expression and sets its value. |
375 | | void defineExpr(Expression const& _e, smtutil::Expression _value); |
376 | | /// Creates the tuple expression and sets its value. |
377 | | void defineExpr(Expression const& _e, std::vector<std::optional<smtutil::Expression>> const& _values); |
378 | | /// Overwrites the current path condition |
379 | | void setPathCondition(smtutil::Expression const& _e); |
380 | | /// Adds a new path condition |
381 | | void pushPathCondition(smtutil::Expression const& _e); |
382 | | /// Remove the last path condition |
383 | | void popPathCondition(); |
384 | | /// Returns the conjunction of all path conditions or True if empty |
385 | | smtutil::Expression currentPathConditions(); |
386 | | /// @returns a human-readable call stack. Used for models. |
387 | | langutil::SecondarySourceLocation callStackMessage(std::vector<CallStackEntry> const& _callStack); |
388 | | /// Copies and pops the last called node. |
389 | | CallStackEntry popCallStack(); |
390 | | /// Adds (_definition, _node) to the callstack. |
391 | | void pushCallStack(CallStackEntry _entry); |
392 | | /// Add to the solver: the given expression implied by the current path conditions |
393 | | void addPathImpliedExpression(smtutil::Expression const& _e); |
394 | | |
395 | | /// Copy the SSA indices of m_variables. |
396 | | VariableIndices copyVariableIndices(); |
397 | | /// Resets the variable indices. |
398 | | void resetVariableIndices(VariableIndices const& _indices); |
399 | | /// Used when starting a new block. |
400 | | virtual void clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function = nullptr); |
401 | | |
402 | | |
403 | | /// @returns variables that are touched in _node's subtree. |
404 | | std::set<VariableDeclaration const*> touchedVariables(ASTNode const& _node); |
405 | | |
406 | | /// @returns the declaration referenced by _expr, if any, |
407 | | /// and nullptr otherwise. |
408 | | Declaration const* expressionToDeclaration(Expression const& _expr) const; |
409 | | |
410 | | /// @returns the VariableDeclaration referenced by an Expression or nullptr. |
411 | | VariableDeclaration const* identifierToVariable(Expression const& _expr) const; |
412 | | |
413 | | /// @returns the MemberAccess <expression>.push if _expr is an empty array push call, |
414 | | /// otherwise nullptr. |
415 | | MemberAccess const* isEmptyPush(Expression const& _expr) const; |
416 | | |
417 | | /// @returns true if the given expression is `this`. |
418 | | /// This means we don't have to abstract away effects of external function calls to this contract. |
419 | | static bool isExternalCallToThis(Expression const* _expr); |
420 | | |
421 | | /// Creates symbolic expressions for the returned values |
422 | | /// and set them as the components of the symbolic tuple. |
423 | | void createReturnedExpressions(FunctionDefinition const* _funDef, Expression const& _calledExpr); |
424 | | |
425 | | /// @returns the symbolic arguments for a function call, |
426 | | /// taking into account attached functions and |
427 | | /// type conversion. |
428 | | std::vector<smtutil::Expression> symbolicArguments( |
429 | | std::vector<ASTPointer<VariableDeclaration>> const& _funParameters, |
430 | | std::vector<Expression const*> const& _arguments, |
431 | | std::optional<Expression const*> _calledExpr |
432 | | ); |
433 | | |
434 | | smtutil::Expression constantExpr(Expression const& _expr, VariableDeclaration const& _var); |
435 | | |
436 | | /// Traverses all source units available collecting free functions |
437 | | /// and internal library functions in m_freeFunctions. |
438 | | void collectFreeFunctions(std::set<SourceUnit const*, ASTNode::CompareByID> const& _sources); |
439 | 53.5k | std::set<FunctionDefinition const*, ASTNode::CompareByID> const& allFreeFunctions() const { return m_freeFunctions; } |
440 | | /// Create symbolic variables for the free constants in all @param _sources. |
441 | | void createFreeConstants(std::set<SourceUnit const*, ASTNode::CompareByID> const& _sources); |
442 | | |
443 | | /// Create symbolic variables for all state variables for all contracts in all @param _sources. |
444 | | void createStateVariables(std::set<SourceUnit const*, ASTNode::CompareByID> const& _sources); |
445 | | |
446 | | /// @returns a note to be added to warnings. |
447 | | std::string extraComment(); |
448 | | |
449 | | struct VerificationTarget |
450 | | { |
451 | | VerificationTargetType type; |
452 | | smtutil::Expression value; |
453 | | smtutil::Expression constraints; |
454 | | }; |
455 | | |
456 | | bool m_arrayAssignmentHappened = false; |
457 | | |
458 | | /// Stores the instances of an Uninterpreted Function applied to arguments. |
459 | | /// These may be direct application of UFs or Array index access. |
460 | | /// Used to retrieve models. |
461 | | std::set<Expression const*> m_uninterpretedTerms; |
462 | | std::vector<smtutil::Expression> m_pathConditions; |
463 | | |
464 | | /// Whether the currently visited block uses checked |
465 | | /// or unchecked arithmetic. |
466 | | bool m_checked = true; |
467 | | |
468 | | langutil::UniqueErrorReporter& m_errorReporter; |
469 | | langutil::UniqueErrorReporter& m_unsupportedErrors; |
470 | | langutil::ErrorReporter& m_provedSafeReporter; |
471 | | |
472 | | /// Stores the current function/modifier call/invocation path. |
473 | | std::vector<CallStackEntry> m_callStack; |
474 | | |
475 | | /// Stack of scopes. |
476 | | std::vector<ScopeOpener const*> m_scopes; |
477 | | |
478 | | /// Returns true if the current function was not visited by |
479 | | /// a function call. |
480 | | bool isRootFunction(); |
481 | | /// Returns true if _funDef was already visited. |
482 | | bool visitedFunction(FunctionDefinition const* _funDef); |
483 | | /// @returns the contract that contains the current FunctionDefinition that is being visited, |
484 | | /// or nullptr if the analysis is not inside a FunctionDefinition. |
485 | | ContractDefinition const* currentScopeContract(); |
486 | | |
487 | | /// @returns FunctionDefinitions of the given contract (including its constructor and inherited methods), |
488 | | /// taking into account overriding of the virtual functions. |
489 | | std::set<FunctionDefinition const*, ASTNode::CompareByID> const& contractFunctions(ContractDefinition const& _contract); |
490 | | /// Cache for the method contractFunctions. |
491 | | std::map<ContractDefinition const*, std::set<FunctionDefinition const*, ASTNode::CompareByID>> m_contractFunctions; |
492 | | |
493 | | /// @returns FunctionDefinitions of the given contract (including its constructor and methods of bases), |
494 | | /// without taking into account overriding of the virtual functions. |
495 | | std::set<FunctionDefinition const*, ASTNode::CompareByID> const& contractFunctionsWithoutVirtual(ContractDefinition const& _contract); |
496 | | /// Cache for the method contractFunctionsWithoutVirtual. |
497 | | std::map<ContractDefinition const*, std::set<FunctionDefinition const*, ASTNode::CompareByID>> m_contractFunctionsWithoutVirtual; |
498 | | |
499 | | /// Depth of visit to modifiers. |
500 | | /// When m_modifierDepth == #modifiers the function can be visited |
501 | | /// when placeholder is visited. |
502 | | /// Needs to be a stack because of function calls. |
503 | | std::vector<int> m_modifierDepthStack; |
504 | | |
505 | | std::map<ContractDefinition const*, ModifierInvocation const*> m_baseConstructorCalls; |
506 | | |
507 | | ContractDefinition const* m_currentContract = nullptr; |
508 | | |
509 | | /// Stores the free functions and internal library functions. |
510 | | /// Those need to be encoded repeatedly for every analyzed contract. |
511 | | std::set<FunctionDefinition const*, ASTNode::CompareByID> m_freeFunctions; |
512 | | |
513 | | /// Stores the context of the encoding. |
514 | | smt::EncodingContext& m_context; |
515 | | |
516 | | ModelCheckerSettings m_settings; |
517 | | |
518 | | /// Character stream for each source, |
519 | | /// used for retrieving source text of expressions for e.g. counter-examples. |
520 | | langutil::CharStreamProvider const& m_charStreamProvider; |
521 | | |
522 | | smt::SymbolicState& state(); |
523 | | |
524 | | private: |
525 | | smtutil::Expression createSelectExpressionForFunction( |
526 | | smtutil::Expression symbFunction, |
527 | | std::vector<frontend::ASTPointer<frontend::Expression const>> const& args, |
528 | | frontend::TypePointers const& inTypes, |
529 | | unsigned long argsActualLength |
530 | | ); |
531 | | }; |
532 | | |
533 | | } |