/src/solidity/libsolidity/formal/EncodingContext.cpp
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 | | #include <libsolidity/formal/EncodingContext.h> |
20 | | |
21 | | #include <libsolidity/ast/AST.h> |
22 | | |
23 | | #include <libsolidity/formal/SymbolicTypes.h> |
24 | | |
25 | | using namespace solidity; |
26 | | using namespace solidity::util; |
27 | | using namespace solidity::frontend::smt; |
28 | | |
29 | | bool EncodingContext::IdCompare::operator()(ASTNode const* lhs, ASTNode const* rhs) const |
30 | 57.5M | { |
31 | 57.5M | return lhs->id() < rhs->id(); |
32 | 57.5M | } |
33 | | |
34 | | EncodingContext::EncodingContext(): |
35 | | m_state(*this) |
36 | 14.6k | { |
37 | 14.6k | } |
38 | | |
39 | | void EncodingContext::reset() |
40 | 63.7k | { |
41 | 63.7k | resetAllVariables(); |
42 | 63.7k | m_expressions.clear(); |
43 | 63.7k | m_globalContext.clear(); |
44 | 63.7k | m_state.reset(); |
45 | 63.7k | m_assertions.clear(); |
46 | 63.7k | } |
47 | | |
48 | | void EncodingContext::resetUniqueId() |
49 | 15.5k | { |
50 | 15.5k | m_nextUniqueId = 0; |
51 | 15.5k | } |
52 | | |
53 | | unsigned EncodingContext::newUniqueId() |
54 | 61.0k | { |
55 | 61.0k | return m_nextUniqueId++; |
56 | 61.0k | } |
57 | | |
58 | | /// Variables. |
59 | | |
60 | | std::shared_ptr<SymbolicVariable> EncodingContext::variable(frontend::VariableDeclaration const& _varDecl) |
61 | 1.96M | { |
62 | 1.96M | solAssert(knownVariable(_varDecl), ""); |
63 | 1.96M | return m_variables[&_varDecl]; |
64 | 1.96M | } |
65 | | |
66 | | bool EncodingContext::createVariable(frontend::VariableDeclaration const& _varDecl) |
67 | 28.6k | { |
68 | 28.6k | solAssert(!knownVariable(_varDecl), ""); |
69 | 28.6k | auto const& type = _varDecl.type(); |
70 | 28.6k | auto result = newSymbolicVariable(*type, _varDecl.name() + "_" + std::to_string(_varDecl.id()), *this); |
71 | 28.6k | m_variables.emplace(&_varDecl, result.second); |
72 | 28.6k | return result.first; |
73 | 28.6k | } |
74 | | |
75 | | bool EncodingContext::knownVariable(frontend::VariableDeclaration const& _varDecl) |
76 | 3.00M | { |
77 | 3.00M | return m_variables.count(&_varDecl); |
78 | 3.00M | } |
79 | | |
80 | | void EncodingContext::resetVariable(frontend::VariableDeclaration const& _variable) |
81 | 188k | { |
82 | 188k | newValue(_variable); |
83 | 188k | setUnknownValue(_variable); |
84 | 188k | } |
85 | | |
86 | | void EncodingContext::resetVariables(std::set<frontend::VariableDeclaration const*> const& _variables) |
87 | 0 | { |
88 | 0 | for (auto const* decl: _variables) |
89 | 0 | resetVariable(*decl); |
90 | 0 | } |
91 | | |
92 | | void EncodingContext::resetVariables(std::function<bool(frontend::VariableDeclaration const&)> const& _filter) |
93 | 137k | { |
94 | 137k | for_each(begin(m_variables), end(m_variables), [&](auto _variable) |
95 | 276k | { |
96 | 276k | if (_filter(*_variable.first)) |
97 | 187k | this->resetVariable(*_variable.first); |
98 | 276k | }); |
99 | 137k | } |
100 | | |
101 | | void EncodingContext::resetAllVariables() |
102 | 96.3k | { |
103 | 172k | resetVariables([&](frontend::VariableDeclaration const&) { return true; }); |
104 | 96.3k | } |
105 | | |
106 | | smtutil::Expression EncodingContext::newValue(frontend::VariableDeclaration const& _decl) |
107 | 199k | { |
108 | 199k | solAssert(knownVariable(_decl), ""); |
109 | 199k | return m_variables.at(&_decl)->increaseIndex(); |
110 | 199k | } |
111 | | |
112 | | void EncodingContext::setZeroValue(frontend::VariableDeclaration const& _decl) |
113 | 39.7k | { |
114 | 39.7k | solAssert(knownVariable(_decl), ""); |
115 | 39.7k | setZeroValue(*m_variables.at(&_decl)); |
116 | 39.7k | } |
117 | | |
118 | | void EncodingContext::setZeroValue(SymbolicVariable& _variable) |
119 | 39.7k | { |
120 | 39.7k | setSymbolicZeroValue(_variable, *this); |
121 | 39.7k | } |
122 | | |
123 | | void EncodingContext::setUnknownValue(frontend::VariableDeclaration const& _decl) |
124 | 205k | { |
125 | 205k | solAssert(knownVariable(_decl), ""); |
126 | 205k | setUnknownValue(*m_variables.at(&_decl)); |
127 | 205k | } |
128 | | |
129 | | void EncodingContext::setUnknownValue(SymbolicVariable& _variable) |
130 | 207k | { |
131 | 207k | setSymbolicUnknownValue(_variable, *this); |
132 | 207k | } |
133 | | |
134 | | /// Expressions |
135 | | |
136 | | std::shared_ptr<SymbolicVariable> EncodingContext::expression(frontend::Expression const& _e) |
137 | 1.11M | { |
138 | 1.11M | if (!knownExpression(_e)) |
139 | 633 | createExpression(_e); |
140 | 1.11M | return m_expressions.at(&_e); |
141 | 1.11M | } |
142 | | |
143 | | bool EncodingContext::createExpression(frontend::Expression const& _e, std::shared_ptr<SymbolicVariable> _symbVar) |
144 | 513k | { |
145 | 513k | solAssert(_e.annotation().type, ""); |
146 | 513k | if (knownExpression(_e)) |
147 | 163k | { |
148 | 163k | expression(_e)->increaseIndex(); |
149 | 163k | return false; |
150 | 163k | } |
151 | 349k | else if (_symbVar) |
152 | 7.68k | { |
153 | 7.68k | m_expressions.emplace(&_e, _symbVar); |
154 | 7.68k | return false; |
155 | 7.68k | } |
156 | 342k | else |
157 | 342k | { |
158 | 342k | auto result = newSymbolicVariable(*_e.annotation().type, "expr_" + std::to_string(_e.id()), *this); |
159 | 342k | m_expressions.emplace(&_e, result.second); |
160 | 342k | return result.first; |
161 | 342k | } |
162 | 513k | } |
163 | | |
164 | | bool EncodingContext::knownExpression(frontend::Expression const& _e) const |
165 | 2.51M | { |
166 | 2.51M | return m_expressions.count(&_e); |
167 | 2.51M | } |
168 | | |
169 | | /// Global variables and functions. |
170 | | |
171 | | std::shared_ptr<SymbolicVariable> EncodingContext::globalSymbol(std::string const& _name) |
172 | 3.11k | { |
173 | 3.11k | solAssert(knownGlobalSymbol(_name), ""); |
174 | 3.11k | return m_globalContext.at(_name); |
175 | 3.11k | } |
176 | | |
177 | | bool EncodingContext::createGlobalSymbol(std::string const& _name, frontend::Expression const& _expr) |
178 | 1.74k | { |
179 | 1.74k | solAssert(!knownGlobalSymbol(_name), ""); |
180 | 1.74k | auto result = newSymbolicVariable(*_expr.annotation().type, _name, *this); |
181 | 1.74k | m_globalContext.emplace(_name, result.second); |
182 | 1.74k | setUnknownValue(*result.second); |
183 | 1.74k | return result.first; |
184 | 1.74k | } |
185 | | |
186 | | bool EncodingContext::knownGlobalSymbol(std::string const& _var) const |
187 | 7.86k | { |
188 | 7.86k | return m_globalContext.count(_var); |
189 | 7.86k | } |
190 | | |
191 | | /// Solver. |
192 | | |
193 | | smtutil::Expression EncodingContext::assertions() |
194 | 276k | { |
195 | 276k | if (m_assertions.empty()) |
196 | 51.3k | return smtutil::Expression(true); |
197 | | |
198 | 225k | return m_assertions.back(); |
199 | 276k | } |
200 | | |
201 | | void EncodingContext::pushSolver() |
202 | 219k | { |
203 | 219k | if (m_accumulateAssertions) |
204 | 34.1k | m_assertions.push_back(assertions()); |
205 | 184k | else |
206 | 184k | m_assertions.emplace_back(true); |
207 | 219k | } |
208 | | |
209 | | void EncodingContext::popSolver() |
210 | 219k | { |
211 | 219k | solAssert(!m_assertions.empty(), ""); |
212 | 219k | m_assertions.pop_back(); |
213 | 219k | } |
214 | | |
215 | | void EncodingContext::addAssertion(smtutil::Expression const& _expr) |
216 | 1.14M | { |
217 | 1.14M | if (m_assertions.empty()) |
218 | 37.8k | m_assertions.push_back(_expr); |
219 | 1.10M | else |
220 | 1.10M | m_assertions.back() = _expr && std::move(m_assertions.back()); |
221 | 1.14M | } |