Coverage Report

Created: 2022-08-24 06:52

/src/solidity/libsolidity/analysis/ControlFlowGraph.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
#pragma once
20
21
#include <libsolidity/ast/AST.h>
22
#include <libsolidity/ast/ASTVisitor.h>
23
#include <liblangutil/ErrorReporter.h>
24
#include <liblangutil/EVMVersion.h>
25
#include <liblangutil/SourceLocation.h>
26
27
#include <map>
28
#include <memory>
29
#include <stack>
30
#include <utility>
31
#include <vector>
32
33
namespace solidity::frontend
34
{
35
36
/**
37
 * Occurrence of a variable in a block of control flow.
38
 * Stores the declaration of the referenced variable, the
39
 * kind of the occurrence and possibly the source location
40
 * at which it occurred.
41
 */
42
class VariableOccurrence
43
{
44
public:
45
  enum class Kind
46
  {
47
    Declaration,
48
    Access,
49
    Return,
50
    Assignment,
51
    InlineAssembly
52
  };
53
  VariableOccurrence(VariableDeclaration const& _declaration, Kind _kind, std::optional<langutil::SourceLocation>  _occurrence = {}):
54
    m_declaration(_declaration), m_occurrenceKind(_kind), m_occurrence(std::move(_occurrence))
55
1.92M
  {
56
1.92M
  }
57
58
  /// Defines a deterministic order on variable occurrences.
59
  bool operator<(VariableOccurrence const& _rhs) const
60
883k
  {
61
883k
    if (m_occurrence && _rhs.m_occurrence)
62
883k
    {
63
883k
      if (*m_occurrence < *_rhs.m_occurrence) return true;
64
330k
      if (*_rhs.m_occurrence < *m_occurrence) return false;
65
330k
    }
66
0
    else if (_rhs.m_occurrence)
67
0
      return true;
68
0
    else if (m_occurrence)
69
0
      return false;
70
71
4.68k
    using KindCompareType = std::underlying_type<VariableOccurrence::Kind>::type;
72
4.68k
    return
73
4.68k
      std::make_pair(m_declaration.id(), static_cast<KindCompareType>(m_occurrenceKind)) <
74
4.68k
      std::make_pair(_rhs.m_declaration.id(), static_cast<KindCompareType>(_rhs.m_occurrenceKind));
75
883k
  }
76
77
1.97M
  VariableDeclaration const& declaration() const { return m_declaration; }
78
1.92M
  Kind kind() const { return m_occurrenceKind; }
79
46.9k
  std::optional<langutil::SourceLocation> const& occurrence() const { return m_occurrence; }
80
private:
81
  /// Declaration of the occurring variable.
82
  VariableDeclaration const& m_declaration;
83
  /// Kind of occurrence.
84
  Kind m_occurrenceKind = Kind::Access;
85
  /// Source location at which the variable occurred, if available (may be nullptr).
86
  std::optional<langutil::SourceLocation> m_occurrence;
87
};
88
89
/**
90
 * Node of the Control Flow Graph.
91
 * The control flow is a directed graph connecting control flow blocks.
92
 * An arc between two nodes indicates that the control flow can possibly
93
 * move from its start node to its end node during execution.
94
 */
95
struct CFGNode
96
{
97
  /// Entry nodes. All CFG nodes from which control flow may move into this node.
98
  std::vector<CFGNode*> entries;
99
  /// Exit nodes. All CFG nodes to which control flow may continue after this node.
100
  std::vector<CFGNode*> exits;
101
  /// Function call done by this node
102
  FunctionCall const* functionCall = nullptr;
103
104
  /// Variable occurrences in the node.
105
  std::vector<VariableOccurrence> variableOccurrences;
106
  // Source location of this control flow block.
107
  langutil::SourceLocation location;
108
};
109
110
/** Describes the control flow of a function. */
111
struct FunctionFlow
112
{
113
39.6k
  virtual ~FunctionFlow() = default;
114
115
  /// Entry node. Control flow of the function starts here.
116
  /// This node is empty and does not have any entries.
117
  CFGNode* entry = nullptr;
118
  /// Exit node. All non-reverting control flow of the function ends here.
119
  /// This node is empty and does not have any exits, but may have multiple entries
120
  /// (e.g. all return statements of the function).
121
  CFGNode* exit = nullptr;
122
  /// Revert node. Control flow of the function in case of revert.
123
  /// This node is empty and does not have any exits, but may have multiple entries
124
  /// (e.g. all assert, require, revert and throw statements).
125
  CFGNode* revert = nullptr;
126
  /// Transaction return node. Destination node for inline assembly "return" calls.
127
  /// This node is empty and does not have any exits, but may have multiple entries
128
  /// (e.g. all inline assembly return calls).
129
  CFGNode* transactionReturn = nullptr;
130
};
131
132
class CFG: private ASTConstVisitor
133
{
134
public:
135
  struct FunctionContractTuple
136
  {
137
    ContractDefinition const* contract = nullptr;
138
    FunctionDefinition const* function = nullptr;
139
140
    // Use AST ids for comparison to keep a deterministic order in the
141
    // containers using this struct
142
    bool operator<(FunctionContractTuple const& _other) const
143
2.39M
    {
144
2.39M
      return
145
2.39M
        std::make_pair(contract ? contract->id() : -1, function->id()) <
146
2.39M
        std::make_pair(_other.contract ? _other.contract->id() : -1, _other.function->id());
147
2.39M
    }
148
  };
149
3.60k
  explicit CFG(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
150
151
  bool constructFlow(ASTNode const& _astRoot);
152
153
  bool visit(FunctionDefinition const& _function) override;
154
  bool visit(ContractDefinition const& _contract) override;
155
156
  /// Get the function flow for the given function, using `_contract` as the
157
  /// most derived contract
158
  /// @param _function function to find the function flow for
159
  /// @param _contract most derived contract or nullptr for free functions
160
  FunctionFlow const& functionFlow(FunctionDefinition const& _function, ContractDefinition const* _contract = nullptr) const;
161
162
  std::map<FunctionContractTuple, std::unique_ptr<FunctionFlow>> const& allFunctionFlows() const
163
7.21k
  {
164
7.21k
    return m_functionControlFlow;
165
7.21k
  }
166
167
  class NodeContainer
168
  {
169
  public:
170
    CFGNode* newNode();
171
  private:
172
    std::vector<std::unique_ptr<CFGNode>> m_nodes;
173
  };
174
private:
175
  langutil::ErrorReporter& m_errorReporter;
176
177
  /// Node container.
178
  /// All nodes allocated during the construction of the control flow graph
179
  /// are owned by the CFG class and stored in this container.
180
  NodeContainer m_nodeContainer;
181
182
  std::map<FunctionContractTuple, std::unique_ptr<FunctionFlow>> m_functionControlFlow;
183
};
184
185
}