Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}