/src/solidity/libsolidity/formal/SymbolicVariables.cpp
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 | | #include <libsolidity/formal/SymbolicVariables.h> |
20 | | |
21 | | #include <libsolidity/ast/AST.h> |
22 | | |
23 | | #include <libsolidity/formal/EncodingContext.h> |
24 | | #include <libsolidity/formal/SymbolicTypes.h> |
25 | | |
26 | | #include <libsolutil/Algorithms.h> |
27 | | |
28 | | using namespace solidity; |
29 | | using namespace solidity::util; |
30 | | using namespace solidity::smtutil; |
31 | | using namespace solidity::frontend; |
32 | | using namespace solidity::frontend::smt; |
33 | | |
34 | | SymbolicVariable::SymbolicVariable( |
35 | | frontend::Type const* _type, |
36 | | frontend::Type const* _originalType, |
37 | | std::string _uniqueName, |
38 | | EncodingContext& _context |
39 | | ): |
40 | 421k | m_type(_type), |
41 | 421k | m_originalType(_originalType), |
42 | 421k | m_uniqueName(std::move(_uniqueName)), |
43 | 421k | m_context(_context), |
44 | 421k | m_ssa(std::make_unique<SSAVariable>()) |
45 | 421k | { |
46 | 421k | solAssert(m_type, ""); |
47 | 421k | m_sort = smtSort(*m_type); |
48 | 421k | solAssert(m_sort, ""); |
49 | 421k | } |
50 | | |
51 | | SymbolicVariable::SymbolicVariable( |
52 | | SortPointer _sort, |
53 | | std::string _uniqueName, |
54 | | EncodingContext& _context |
55 | | ): |
56 | 221k | m_sort(std::move(_sort)), |
57 | 221k | m_uniqueName(std::move(_uniqueName)), |
58 | 221k | m_context(_context), |
59 | 221k | m_ssa(std::make_unique<SSAVariable>()) |
60 | 221k | { |
61 | 221k | solAssert(m_sort, ""); |
62 | 221k | } |
63 | | |
64 | | smtutil::Expression SymbolicVariable::currentValue(frontend::Type const*) const |
65 | 7.98M | { |
66 | 7.98M | return valueAtIndex(m_ssa->index()); |
67 | 7.98M | } |
68 | | |
69 | | std::string SymbolicVariable::currentName() const |
70 | 22.9k | { |
71 | 22.9k | return uniqueSymbol(m_ssa->index()); |
72 | 22.9k | } |
73 | | |
74 | | smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const |
75 | 11.0M | { |
76 | 11.0M | return m_context.newVariable(uniqueSymbol(_index), m_sort); |
77 | 11.0M | } |
78 | | |
79 | | std::string SymbolicVariable::nameAtIndex(unsigned _index) const |
80 | 0 | { |
81 | 0 | return uniqueSymbol(_index); |
82 | 0 | } |
83 | | |
84 | | std::string SymbolicVariable::uniqueSymbol(unsigned _index) const |
85 | 11.0M | { |
86 | 11.0M | return m_uniqueName + "_" + std::to_string(_index); |
87 | 11.0M | } |
88 | | |
89 | | smtutil::Expression SymbolicVariable::resetIndex() |
90 | 2.17M | { |
91 | 2.17M | m_ssa->resetIndex(); |
92 | 2.17M | return currentValue(); |
93 | 2.17M | } |
94 | | |
95 | | smtutil::Expression SymbolicVariable::setIndex(unsigned _index) |
96 | 22.4k | { |
97 | 22.4k | m_ssa->setIndex(_index); |
98 | 22.4k | return currentValue(); |
99 | 22.4k | } |
100 | | |
101 | | smtutil::Expression SymbolicVariable::increaseIndex() |
102 | 1.23M | { |
103 | 1.23M | ++(*m_ssa); |
104 | 1.23M | return currentValue(); |
105 | 1.23M | } |
106 | | |
107 | | SymbolicBoolVariable::SymbolicBoolVariable( |
108 | | frontend::Type const* _type, |
109 | | std::string _uniqueName, |
110 | | EncodingContext& _context |
111 | | ): |
112 | 16.7k | SymbolicVariable(_type, _type, std::move(_uniqueName), _context) |
113 | 16.7k | { |
114 | 16.7k | solAssert(m_type->category() == frontend::Type::Category::Bool, ""); |
115 | 16.7k | } |
116 | | |
117 | | SymbolicIntVariable::SymbolicIntVariable( |
118 | | frontend::Type const* _type, |
119 | | frontend::Type const* _originalType, |
120 | | std::string _uniqueName, |
121 | | EncodingContext& _context |
122 | | ): |
123 | 269k | SymbolicVariable(_type, _originalType, std::move(_uniqueName), _context) |
124 | 269k | { |
125 | 269k | solAssert(isNumber(*m_type), ""); |
126 | 269k | } |
127 | | |
128 | | SymbolicAddressVariable::SymbolicAddressVariable( |
129 | | std::string _uniqueName, |
130 | | EncodingContext& _context |
131 | | ): |
132 | 24.6k | SymbolicIntVariable(TypeProvider::uint(160), TypeProvider::uint(160), std::move(_uniqueName), _context) |
133 | 24.6k | { |
134 | 24.6k | } |
135 | | |
136 | | SymbolicFixedBytesVariable::SymbolicFixedBytesVariable( |
137 | | frontend::Type const* _originalType, |
138 | | unsigned _numBytes, |
139 | | std::string _uniqueName, |
140 | | EncodingContext& _context |
141 | | ): |
142 | 8.95k | SymbolicIntVariable(TypeProvider::uint(_numBytes * 8), _originalType, std::move(_uniqueName), _context) |
143 | 8.95k | { |
144 | 8.95k | } |
145 | | |
146 | | SymbolicFunctionVariable::SymbolicFunctionVariable( |
147 | | frontend::Type const* _type, |
148 | | std::string _uniqueName, |
149 | | EncodingContext& _context |
150 | | ): |
151 | 11.3k | SymbolicVariable(_type, _type, std::move(_uniqueName), _context), |
152 | 11.3k | m_declaration(m_context.newVariable(currentName(), m_sort)) |
153 | 11.3k | { |
154 | 11.3k | solAssert(m_type->category() == frontend::Type::Category::Function, ""); |
155 | 11.3k | } |
156 | | |
157 | | SymbolicFunctionVariable::SymbolicFunctionVariable( |
158 | | SortPointer _sort, |
159 | | std::string _uniqueName, |
160 | | EncodingContext& _context |
161 | | ): |
162 | 0 | SymbolicVariable(std::move(_sort), std::move(_uniqueName), _context), |
163 | 0 | m_declaration(m_context.newVariable(currentName(), m_sort)) |
164 | 0 | { |
165 | 0 | solAssert(m_sort->kind == Kind::Function, ""); |
166 | 0 | } |
167 | | |
168 | | smtutil::Expression SymbolicFunctionVariable::currentValue(frontend::Type const* _targetType) const |
169 | 25.0k | { |
170 | 25.0k | return m_abstract.currentValue(_targetType); |
171 | 25.0k | } |
172 | | |
173 | | smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const |
174 | 0 | { |
175 | 0 | return m_declaration; |
176 | 0 | } |
177 | | |
178 | | smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const |
179 | 6.63k | { |
180 | 6.63k | return m_abstract.valueAtIndex(_index); |
181 | 6.63k | } |
182 | | |
183 | | smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const |
184 | 0 | { |
185 | 0 | return SymbolicVariable::valueAtIndex(_index); |
186 | 0 | } |
187 | | |
188 | | smtutil::Expression SymbolicFunctionVariable::resetIndex() |
189 | 4.48k | { |
190 | 4.48k | SymbolicVariable::resetIndex(); |
191 | 4.48k | return m_abstract.resetIndex(); |
192 | 4.48k | } |
193 | | |
194 | | smtutil::Expression SymbolicFunctionVariable::setIndex(unsigned _index) |
195 | 121 | { |
196 | 121 | SymbolicVariable::setIndex(_index); |
197 | 121 | return m_abstract.setIndex(_index); |
198 | 121 | } |
199 | | |
200 | | smtutil::Expression SymbolicFunctionVariable::increaseIndex() |
201 | 11.6k | { |
202 | 11.6k | ++(*m_ssa); |
203 | 11.6k | resetDeclaration(); |
204 | 11.6k | m_abstract.increaseIndex(); |
205 | 11.6k | return m_abstract.currentValue(); |
206 | 11.6k | } |
207 | | |
208 | | smtutil::Expression SymbolicFunctionVariable::operator()(std::vector<smtutil::Expression> const& _arguments) const |
209 | 0 | { |
210 | 0 | return m_declaration(_arguments); |
211 | 0 | } |
212 | | |
213 | | void SymbolicFunctionVariable::resetDeclaration() |
214 | 11.6k | { |
215 | 11.6k | m_declaration = m_context.newVariable(currentName(), m_sort); |
216 | 11.6k | } |
217 | | |
218 | | SymbolicEnumVariable::SymbolicEnumVariable( |
219 | | frontend::Type const* _type, |
220 | | std::string _uniqueName, |
221 | | EncodingContext& _context |
222 | | ): |
223 | 595 | SymbolicVariable(_type, _type, std::move(_uniqueName), _context) |
224 | 595 | { |
225 | 595 | solAssert(isEnum(*m_type), ""); |
226 | 595 | } |
227 | | |
228 | | SymbolicTupleVariable::SymbolicTupleVariable( |
229 | | frontend::Type const* _type, |
230 | | std::string _uniqueName, |
231 | | EncodingContext& _context |
232 | | ): |
233 | 20.1k | SymbolicVariable(_type, _type, std::move(_uniqueName), _context) |
234 | 20.1k | { |
235 | 20.1k | solAssert(isTuple(*m_type), ""); |
236 | 20.1k | } |
237 | | |
238 | | SymbolicTupleVariable::SymbolicTupleVariable( |
239 | | SortPointer _sort, |
240 | | std::string _uniqueName, |
241 | | EncodingContext& _context |
242 | | ): |
243 | 219k | SymbolicVariable(std::move(_sort), std::move(_uniqueName), _context) |
244 | 219k | { |
245 | 219k | solAssert(m_sort->kind == Kind::Tuple, ""); |
246 | 219k | } |
247 | | |
248 | | smtutil::Expression SymbolicTupleVariable::currentValue(frontend::Type const* _targetType) const |
249 | 4.23M | { |
250 | 4.23M | if (!_targetType || sort() == smtSort(*_targetType)) |
251 | 4.23M | return SymbolicVariable::currentValue(); |
252 | | |
253 | 2.09k | auto thisTuple = std::dynamic_pointer_cast<TupleSort>(sort()); |
254 | 2.09k | auto otherTuple = std::dynamic_pointer_cast<TupleSort>(smtSort(*_targetType)); |
255 | 2.09k | solAssert(thisTuple && otherTuple, ""); |
256 | 2.09k | solAssert(thisTuple->components.size() == otherTuple->components.size(), ""); |
257 | 2.09k | std::vector<smtutil::Expression> args; |
258 | 6.30k | for (size_t i = 0; i < thisTuple->components.size(); ++i) |
259 | 4.20k | args.emplace_back(component(i, type(), _targetType)); |
260 | 2.09k | return smtutil::Expression::tuple_constructor( |
261 | 2.09k | smtutil::Expression(std::make_shared<smtutil::SortSort>(smtSort(*_targetType)), ""), |
262 | 2.09k | args |
263 | 2.09k | ); |
264 | 4.23M | } |
265 | | |
266 | | std::vector<SortPointer> const& SymbolicTupleVariable::components() const |
267 | 9.68k | { |
268 | 9.68k | auto tupleSort = std::dynamic_pointer_cast<TupleSort>(m_sort); |
269 | 9.68k | solAssert(tupleSort, ""); |
270 | 9.68k | return tupleSort->components; |
271 | 9.68k | } |
272 | | |
273 | | smtutil::Expression SymbolicTupleVariable::component( |
274 | | size_t _index, |
275 | | frontend::Type const* _fromType, |
276 | | frontend::Type const* _toType |
277 | | ) const |
278 | 951k | { |
279 | 951k | std::optional<smtutil::Expression> conversion = symbolicTypeConversion(_fromType, _toType); |
280 | 951k | if (conversion) |
281 | 20 | return *conversion; |
282 | | |
283 | 951k | return smtutil::Expression::tuple_get(currentValue(), _index); |
284 | 951k | } |
285 | | |
286 | | SymbolicArrayVariable::SymbolicArrayVariable( |
287 | | frontend::Type const* _type, |
288 | | frontend::Type const* _originalType, |
289 | | std::string _uniqueName, |
290 | | EncodingContext& _context |
291 | | ): |
292 | 96.5k | SymbolicVariable(_type, _originalType, std::move(_uniqueName), _context), |
293 | 96.5k | m_pair( |
294 | 96.5k | smtSort(*_type), |
295 | 96.5k | m_uniqueName + "_length_pair", |
296 | 96.5k | m_context |
297 | 96.5k | ) |
298 | 96.5k | { |
299 | 96.5k | solAssert(isArray(*m_type) || isMapping(*m_type), ""); |
300 | 96.5k | } |
301 | | |
302 | | SymbolicArrayVariable::SymbolicArrayVariable( |
303 | | SortPointer _sort, |
304 | | std::string _uniqueName, |
305 | | EncodingContext& _context |
306 | | ): |
307 | 242 | SymbolicVariable(std::move(_sort), std::move(_uniqueName), _context), |
308 | 242 | m_pair( |
309 | 242 | std::make_shared<TupleSort>( |
310 | 242 | "array_length_pair", |
311 | 242 | std::vector<std::string>{"array", "length"}, |
312 | 242 | std::vector<SortPointer>{m_sort, SortProvider::uintSort} |
313 | 242 | ), |
314 | 242 | m_uniqueName + "_array_length_pair", |
315 | 242 | m_context |
316 | 242 | ) |
317 | 242 | { |
318 | 242 | solAssert(m_sort->kind == Kind::Array, ""); |
319 | 242 | } |
320 | | |
321 | | smtutil::Expression SymbolicArrayVariable::currentValue(frontend::Type const* _targetType) const |
322 | 787k | { |
323 | 787k | std::optional<smtutil::Expression> conversion = symbolicTypeConversion(m_originalType, _targetType); |
324 | 787k | if (conversion) |
325 | 750 | return *conversion; |
326 | | |
327 | 786k | return m_pair.currentValue(); |
328 | 787k | } |
329 | | |
330 | | smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const |
331 | 179k | { |
332 | 179k | return m_pair.valueAtIndex(_index); |
333 | 179k | } |
334 | | |
335 | | smtutil::Expression SymbolicArrayVariable::elements() const |
336 | 82.5k | { |
337 | 82.5k | return m_pair.component(0); |
338 | 82.5k | } |
339 | | |
340 | | smtutil::Expression SymbolicArrayVariable::length() const |
341 | 54.0k | { |
342 | 54.0k | return m_pair.component(1); |
343 | 54.0k | } |
344 | | |
345 | | SymbolicStructVariable::SymbolicStructVariable( |
346 | | frontend::Type const* _type, |
347 | | std::string _uniqueName, |
348 | | EncodingContext& _context |
349 | | ): |
350 | 6.36k | SymbolicVariable(_type, _type, std::move(_uniqueName), _context) |
351 | 6.36k | { |
352 | 6.36k | solAssert(isNonRecursiveStruct(*m_type), ""); |
353 | 6.36k | auto const* structType = dynamic_cast<StructType const*>(_type); |
354 | 6.36k | solAssert(structType, ""); |
355 | 6.36k | auto const& members = structType->structDefinition().members(); |
356 | 19.4k | for (unsigned i = 0; i < members.size(); ++i) |
357 | 13.0k | { |
358 | 13.0k | solAssert(members.at(i), ""); |
359 | 13.0k | m_memberIndices.emplace(members.at(i)->name(), i); |
360 | 13.0k | } |
361 | 6.36k | } |
362 | | |
363 | | smtutil::Expression SymbolicStructVariable::member(std::string const& _member) const |
364 | 14.6k | { |
365 | 14.6k | return smtutil::Expression::tuple_get(currentValue(), m_memberIndices.at(_member)); |
366 | 14.6k | } |
367 | | |
368 | | smtutil::Expression SymbolicStructVariable::assignMember(std::string const& _member, smtutil::Expression const& _memberValue) |
369 | 1.82k | { |
370 | 1.82k | auto const* structType = dynamic_cast<StructType const*>(m_type); |
371 | 1.82k | solAssert(structType, ""); |
372 | 1.82k | auto const& structDef = structType->structDefinition(); |
373 | 1.82k | auto const& structMembers = structDef.members(); |
374 | 1.82k | auto oldMembers = applyMap( |
375 | 1.82k | structMembers, |
376 | 4.31k | [&](auto _member) { return member(_member->name()); } |
377 | 1.82k | ); |
378 | 1.82k | increaseIndex(); |
379 | 6.14k | for (unsigned i = 0; i < structMembers.size(); ++i) |
380 | 4.31k | { |
381 | 4.31k | auto const& memberName = structMembers.at(i)->name(); |
382 | 4.31k | auto newMember = memberName == _member ? _memberValue : oldMembers.at(i); |
383 | 4.31k | m_context.addAssertion(member(memberName) == newMember); |
384 | 4.31k | } |
385 | | |
386 | 1.82k | return currentValue(); |
387 | 1.82k | } |
388 | | |
389 | | smtutil::Expression SymbolicStructVariable::assignAllMembers(std::vector<smtutil::Expression> const& _memberValues) |
390 | 230 | { |
391 | 230 | auto structType = dynamic_cast<StructType const*>(m_type); |
392 | 230 | solAssert(structType, ""); |
393 | | |
394 | 230 | auto const& structDef = structType->structDefinition(); |
395 | 230 | auto const& structMembers = structDef.members(); |
396 | 230 | solAssert(_memberValues.size() == structMembers.size(), ""); |
397 | 230 | increaseIndex(); |
398 | 632 | for (unsigned i = 0; i < _memberValues.size(); ++i) |
399 | 402 | m_context.addAssertion(_memberValues[i] == member(structMembers[i]->name())); |
400 | | |
401 | 230 | return currentValue(); |
402 | 230 | } |