Coverage Report

Created: 2022-08-24 06:55

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