Coverage Report

Created: 2025-09-08 08:10

/src/solidity/libsolidity/formal/BMC.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/BMC.h>
20
21
#include <libsolidity/formal/Cvc5SMTLib2Interface.h>
22
#include <libsolidity/formal/SymbolicTypes.h>
23
#include <libsolidity/formal/Z3SMTLib2Interface.h>
24
25
#include <libsmtutil/SMTLib2Interface.h>
26
#include <libsmtutil/SMTPortfolio.h>
27
28
#include <liblangutil/CharStream.h>
29
#include <liblangutil/CharStreamProvider.h>
30
31
#include <utility>
32
33
using namespace solidity;
34
using namespace solidity::util;
35
using namespace solidity::langutil;
36
using namespace solidity::frontend;
37
using namespace solidity::frontend::smt;
38
using namespace solidity::smtutil;
39
40
BMC::BMC(
41
  smt::EncodingContext& _context,
42
  UniqueErrorReporter& _errorReporter,
43
  UniqueErrorReporter& _unsupportedErrorReporter,
44
  ErrorReporter& _provedSafeReporter,
45
  std::map<h256, std::string> const& _smtlib2Responses,
46
  ReadCallback::Callback const& _smtCallback,
47
  ModelCheckerSettings _settings,
48
  CharStreamProvider const& _charStreamProvider
49
):
50
  SMTEncoder(_context, _settings, _errorReporter, _unsupportedErrorReporter, _provedSafeReporter, _charStreamProvider)
51
15.5k
{
52
15.5k
  std::vector<std::unique_ptr<BMCSolverInterface>> solvers;
53
15.5k
  if (_settings.solvers.smtlib2)
54
14.9k
    solvers.emplace_back(std::make_unique<SMTLib2Interface>(_smtlib2Responses, _smtCallback, _settings.timeout));
55
15.5k
  if (_settings.solvers.cvc5)
56
0
    solvers.emplace_back(std::make_unique<Cvc5SMTLib2Interface>(_smtCallback, _settings.timeout));
57
15.5k
  if (_settings.solvers.z3 )
58
597
    solvers.emplace_back(std::make_unique<Z3SMTLib2Interface>(_smtCallback, _settings.timeout));
59
15.5k
  m_interface = std::make_unique<SMTPortfolio>(std::move(solvers), _settings.timeout);
60
15.5k
}
61
62
void BMC::analyze(SourceUnit const& _source, std::map<ASTNode const*, std::set<VerificationTargetType>, smt::EncodingContext::IdCompare> _solvedTargets)
63
16.5k
{
64
  // At this point every enabled solver is available.
65
16.5k
  if (!m_settings.solvers.cvc5 && !m_settings.solvers.smtlib2 && !m_settings.solvers.z3)
66
0
  {
67
0
    m_errorReporter.warning(
68
0
      7710_error,
69
0
      SourceLocation(),
70
0
      "BMC analysis was not possible since no SMT solver was found and enabled."
71
0
      " The accepted solvers for BMC are cvc5 and z3."
72
0
    );
73
0
    return;
74
0
  }
75
76
16.5k
  SMTEncoder::resetSourceAnalysis();
77
78
16.5k
  state().prepareForSourceUnit(_source, false);
79
16.5k
  m_solvedTargets = std::move(_solvedTargets);
80
16.5k
  m_context.setSolver(m_interface.get());
81
16.5k
  m_context.reset();
82
16.5k
  m_context.setAssertionAccumulation(true);
83
16.5k
  auto const& sources = sourceDependencies(_source);
84
16.5k
  createFreeConstants(sources);
85
16.5k
  createStateVariables(sources);
86
16.5k
  m_unprovedAmt = 0;
87
88
16.5k
  _source.accept(*this);
89
90
16.5k
  if (m_unprovedAmt > 0 && !m_settings.showUnproved)
91
2.09k
    m_errorReporter.warning(
92
2.09k
      2788_error,
93
2.09k
      {},
94
2.09k
      "BMC: " +
95
2.09k
      std::to_string(m_unprovedAmt) +
96
2.09k
      " verification condition(s) could not be proved." +
97
2.09k
      " Enable the model checker option \"show unproved\" to see all of them." +
98
2.09k
      " Consider choosing a specific contract to be verified in order to reduce the solving problems." +
99
2.09k
      " Consider increasing the timeout per query."
100
2.09k
    );
101
102
16.5k
  if (!m_settings.showProvedSafe && !m_safeTargets.empty())
103
0
  {
104
0
    std::size_t provedSafeNum = 0;
105
0
    for (auto&& [_, targets]: m_safeTargets)
106
0
      provedSafeNum += targets.size();
107
0
    m_errorReporter.info(
108
0
      6002_error,
109
0
      "BMC: " +
110
0
      std::to_string(provedSafeNum) +
111
0
      " verification condition(s) proved safe!" +
112
0
      " Enable the model checker option \"show proved safe\" to see all of them."
113
0
    );
114
0
  }
115
16.5k
  else if (m_settings.showProvedSafe)
116
0
    for (auto const& [node, targets]: m_safeTargets)
117
0
      for (auto const& target: targets)
118
0
        m_provedSafeReporter.info(
119
0
          2961_error,
120
0
          node->location(),
121
0
          "BMC: " +
122
0
          targetDescription(target) +
123
0
          " check is safe!"
124
0
        );
125
126
  // If this check is true, Z3 and cvc5 are not available
127
  // and the query answers were not provided, since SMTPortfolio
128
  // guarantees that SmtLib2Interface is the first solver, if enabled.
129
16.5k
  if (
130
16.5k
    !m_interface->unhandledQueries().empty() &&
131
16.5k
    m_interface->solvers() == 1 &&
132
16.5k
    m_settings.solvers.smtlib2
133
16.5k
  )
134
2.57k
    m_errorReporter.warning(
135
2.57k
      8084_error,
136
2.57k
      SourceLocation(),
137
2.57k
      "BMC analysis was not possible. No SMT solver (Z3 or cvc5) was available."
138
2.57k
      " None of the installed solvers was enabled."
139
2.57k
    );
140
16.5k
}
141
142
bool BMC::shouldInlineFunctionCall(
143
  FunctionCall const& _funCall,
144
  ContractDefinition const* _scopeContract,
145
  ContractDefinition const* _contextContract
146
)
147
5.96k
{
148
5.96k
  auto funDef = functionCallToDefinition(_funCall, _scopeContract, _contextContract);
149
5.96k
  if (!funDef || !funDef->isImplemented())
150
1.05k
    return false;
151
152
4.90k
  FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
153
4.90k
  if (funType.kind() == FunctionType::Kind::External)
154
956
    return isExternalCallToThis(&_funCall.expression());
155
3.95k
  else if (funType.kind() != FunctionType::Kind::Internal)
156
211
    return false;
157
158
3.74k
  return true;
159
4.90k
}
160
161
/// AST visitors.
162
163
bool BMC::visit(ContractDefinition const& _contract)
164
17.5k
{
165
  // Raises UnimplementedFeatureError in the presence of transient storage variables
166
17.5k
  TransientDataLocationChecker checker(_contract);
167
168
17.5k
  initContract(_contract);
169
170
17.5k
  SMTEncoder::visit(_contract);
171
172
17.5k
  return false;
173
17.5k
}
174
175
void BMC::endVisit(ContractDefinition const& _contract)
176
17.5k
{
177
17.5k
  if (auto constructor = _contract.constructor())
178
1.80k
    constructor->accept(*this);
179
15.7k
  else
180
15.7k
  {
181
    /// Visiting implicit constructor - we need a dummy callstack frame
182
15.7k
    pushCallStack({nullptr, nullptr});
183
15.7k
    inlineConstructorHierarchy(_contract);
184
15.7k
    popCallStack();
185
    /// Check targets created by state variable initialization.
186
15.7k
    checkVerificationTargets();
187
15.7k
    m_verificationTargets.clear();
188
15.7k
  }
189
190
17.5k
  SMTEncoder::endVisit(_contract);
191
17.5k
}
192
193
bool BMC::visit(FunctionDefinition const& _function)
194
20.4k
{
195
  // Free functions need to be visited in the context of a contract.
196
20.4k
  if (!m_currentContract)
197
939
    return false;
198
199
19.5k
  auto contract = dynamic_cast<ContractDefinition const*>(_function.scope());
200
19.5k
  auto const& hierarchy = m_currentContract->annotation().linearizedBaseContracts;
201
19.5k
  if (contract && find(hierarchy.begin(), hierarchy.end(), contract) == hierarchy.end())
202
182
    createStateVariables(*contract);
203
204
19.5k
  if (m_callStack.empty())
205
17.0k
  {
206
17.0k
    reset();
207
17.0k
    initFunction(_function);
208
17.0k
    if (_function.isConstructor() || _function.isPublic())
209
15.9k
      m_context.addAssertion(state().txTypeConstraints() && state().txFunctionConstraints(_function));
210
17.0k
    resetStateVariables();
211
17.0k
  }
212
213
19.5k
  if (_function.isConstructor())
214
2.37k
  {
215
2.37k
    solAssert(contract, "");
216
2.37k
    inlineConstructorHierarchy(*contract);
217
2.37k
  }
218
219
  /// Already visits the children.
220
19.5k
  SMTEncoder::visit(_function);
221
222
19.5k
  return false;
223
19.5k
}
224
225
void BMC::endVisit(FunctionDefinition const& _function)
226
20.4k
{
227
  // Free functions need to be visited in the context of a contract.
228
20.4k
  if (!m_currentContract)
229
939
    return;
230
231
19.5k
  if (isRootFunction())
232
17.0k
  {
233
17.0k
    checkVerificationTargets();
234
17.0k
    m_verificationTargets.clear();
235
17.0k
    m_pathConditions.clear();
236
17.0k
  }
237
238
19.5k
  SMTEncoder::endVisit(_function);
239
19.5k
}
240
241
bool BMC::visit(IfStatement const& _node)
242
872
{
243
872
  auto indicesBeforePush = copyVariableIndices();
244
  // This check needs to be done in its own context otherwise
245
  // constraints from the If body might influence it.
246
872
  m_context.pushSolver();
247
872
  _node.condition().accept(*this);
248
249
872
  checkIfConditionIsConstant(_node.condition());
250
251
872
  m_context.popSolver();
252
872
  resetVariableIndices(std::move(indicesBeforePush));
253
254
872
  _node.condition().accept(*this);
255
872
  auto conditionExpr = expr(_node.condition());
256
  // visit true branch
257
872
  auto [indicesEndTrue, trueEndPathCondition] = visitBranch(&_node.trueStatement(), conditionExpr);
258
259
  // visit false branch
260
872
  decltype(indicesEndTrue) indicesEndFalse;
261
872
  auto falseEndPathCondition = currentPathConditions() && !conditionExpr;
262
872
  if (_node.falseStatement())
263
110
    std::tie(indicesEndFalse, falseEndPathCondition) = visitBranch(_node.falseStatement(), !conditionExpr);
264
762
  else
265
762
    indicesEndFalse = copyVariableIndices();
266
267
  // merge the information from branches
268
872
  setPathCondition(trueEndPathCondition || falseEndPathCondition);
269
872
  mergeVariables(expr(_node.condition()), indicesEndTrue, indicesEndFalse);
270
271
872
  return false;
272
872
}
273
274
bool BMC::visit(Conditional const& _op)
275
561
{
276
561
  auto indicesBeforePush = copyVariableIndices();
277
561
  m_context.pushSolver();
278
561
  _op.condition().accept(*this);
279
561
  checkIfConditionIsConstant(_op.condition());
280
561
  m_context.popSolver();
281
561
  resetVariableIndices(std::move(indicesBeforePush));
282
283
561
  SMTEncoder::visit(_op);
284
285
561
  return false;
286
561
}
287
288
// Unrolls while or do-while loop
289
bool BMC::visit(WhileStatement const& _node)
290
141
{
291
141
  unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1);
292
141
  smtutil::Expression broke(false);
293
141
  smtutil::Expression loopCondition(true);
294
141
  if (_node.isDoWhile())
295
28
  {
296
56
    for (unsigned int i = 0; i < bmcLoopIterations; ++i)
297
28
    {
298
28
      m_loopCheckpoints.emplace();
299
300
28
      auto indicesBefore = copyVariableIndices();
301
28
      _node.body().accept(*this);
302
303
28
      auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints();
304
305
28
      auto indicesBreak = copyVariableIndices();
306
28
      _node.condition().accept(*this);
307
28
      mergeVariables(
308
28
        !brokeInCurrentIteration,
309
28
        copyVariableIndices(),
310
28
        indicesBreak
311
28
      );
312
313
28
      mergeVariables(
314
28
        broke || !loopCondition,
315
28
        indicesBefore,
316
28
        copyVariableIndices()
317
28
      );
318
28
      loopCondition = loopCondition && expr(_node.condition());
319
28
      broke = broke || brokeInCurrentIteration;
320
28
      m_loopCheckpoints.pop();
321
28
    }
322
28
    if (bmcLoopIterations > 0)
323
28
      m_context.addAssertion(!loopCondition || broke);
324
28
  }
325
113
  else {
326
113
    smtutil::Expression loopConditionOnPreviousIterations(true);
327
226
    for (unsigned int i = 0; i < bmcLoopIterations; ++i)
328
113
    {
329
113
      m_loopCheckpoints.emplace();
330
113
      auto indicesBefore = copyVariableIndices();
331
113
      _node.condition().accept(*this);
332
113
      loopCondition = expr(_node.condition());
333
334
113
      auto indicesAfterCondition = copyVariableIndices();
335
336
113
      pushPathCondition(loopCondition);
337
113
      _node.body().accept(*this);
338
113
      popPathCondition();
339
340
113
      auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints();
341
342
      // merges indices modified when accepting loop condition that no longer holds
343
113
      mergeVariables(
344
113
        !loopCondition,
345
113
        indicesAfterCondition,
346
113
        copyVariableIndices()
347
113
      );
348
349
      // handles breaks in previous iterations
350
      // breaks in current iterations are handled when traversing loop checkpoints
351
      // handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
352
113
      mergeVariables(
353
113
        broke || !loopConditionOnPreviousIterations,
354
113
        indicesBefore,
355
113
        copyVariableIndices()
356
113
      );
357
113
      m_loopCheckpoints.pop();
358
113
      broke = broke || brokeInCurrentIteration;
359
113
      loopConditionOnPreviousIterations = loopConditionOnPreviousIterations && loopCondition;
360
113
    }
361
113
    if (bmcLoopIterations > 0)
362
113
    {
363
      //after loop iterations are done, we check the loop condition last final time
364
113
      auto indices = copyVariableIndices();
365
113
      m_loopCheckpoints.emplace();
366
113
      _node.condition().accept(*this);
367
113
      m_loopCheckpoints.pop();
368
113
      loopCondition = expr(_node.condition());
369
      // assert that the loop is complete
370
113
      m_context.addAssertion(!loopCondition || broke || !loopConditionOnPreviousIterations);
371
113
      mergeVariables(
372
113
        broke || !loopConditionOnPreviousIterations,
373
113
        indices,
374
113
        copyVariableIndices()
375
113
      );
376
113
    }
377
113
  }
378
141
  m_loopExecutionHappened = true;
379
141
  return false;
380
141
}
381
382
// Unrolls for loop
383
bool BMC::visit(ForStatement const& _node)
384
582
{
385
582
  if (_node.initializationExpression())
386
515
    _node.initializationExpression()->accept(*this);
387
388
582
  smtutil::Expression broke(false);
389
582
  smtutil::Expression forCondition(true);
390
582
  smtutil::Expression forConditionOnPreviousIterations(true);
391
582
  unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1);
392
1.16k
  for (unsigned int i = 0; i < bmcLoopIterations; ++i)
393
582
  {
394
582
    auto indicesBefore = copyVariableIndices();
395
582
    m_loopCheckpoints.emplace();
396
582
    if (_node.condition())
397
541
    {
398
541
      _node.condition()->accept(*this);
399
      // values in loop condition might change during loop iteration
400
541
      forCondition = expr(*_node.condition());
401
541
    }
402
582
    auto indicesAfterCondition = copyVariableIndices();
403
404
582
    pushPathCondition(forCondition);
405
582
    _node.body().accept(*this);
406
407
582
    auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints();
408
409
    // accept loop expression if there was no break
410
582
    if (_node.loopExpression())
411
513
    {
412
513
      auto indicesBreak = copyVariableIndices();
413
513
      _node.loopExpression()->accept(*this);
414
513
      mergeVariables(
415
513
        !brokeInCurrentIteration,
416
513
        copyVariableIndices(),
417
513
        indicesBreak
418
513
      );
419
513
    }
420
582
    popPathCondition();
421
422
    // merges indices modified when accepting loop condition that does no longer hold
423
582
    mergeVariables(
424
582
      !forCondition,
425
582
      indicesAfterCondition,
426
582
      copyVariableIndices()
427
582
    );
428
429
    // handles breaks in previous iterations
430
    // breaks in current iterations are handled when traversing loop checkpoints
431
    // handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
432
582
    mergeVariables(
433
582
      broke || !forConditionOnPreviousIterations,
434
582
      indicesBefore,
435
582
      copyVariableIndices()
436
582
    );
437
582
    m_loopCheckpoints.pop();
438
582
    broke = broke || brokeInCurrentIteration;
439
582
    forConditionOnPreviousIterations = forConditionOnPreviousIterations && forCondition;
440
582
  }
441
582
  if (bmcLoopIterations > 0)
442
582
  {
443
    //after loop iterations are done, we check the loop condition last final time
444
582
    auto indices = copyVariableIndices();
445
582
    if (_node.condition())
446
541
    {
447
541
      m_loopCheckpoints.emplace();
448
541
      _node.condition()->accept(*this);
449
541
      forCondition = expr(*_node.condition());
450
541
      m_loopCheckpoints.pop();
451
541
    }
452
    // assert that the loop is complete
453
582
    m_context.addAssertion(!forCondition || broke || !forConditionOnPreviousIterations);
454
582
    mergeVariables(
455
582
      broke || !forConditionOnPreviousIterations,
456
582
      indices,
457
582
      copyVariableIndices()
458
582
    );
459
582
  }
460
582
  m_loopExecutionHappened = true;
461
582
  return false;
462
582
}
463
464
// merges variables based on loop control statements
465
// returns expression indicating whether there was a break in current loop unroll iteration
466
smtutil::Expression BMC::mergeVariablesFromLoopCheckpoints()
467
723
{
468
723
  smtutil::Expression continues(false);
469
723
  smtutil::Expression brokeInCurrentIteration(false);
470
723
  for (auto const& loopControl: m_loopCheckpoints.top())
471
141
  {
472
    // use SSAs associated with this break statement only if
473
    // loop didn't break or continue earlier in the iteration
474
    // loop condition is included in break path conditions
475
141
    mergeVariables(
476
141
      !brokeInCurrentIteration && !continues && loopControl.pathConditions,
477
141
      loopControl.variableIndices,
478
141
      copyVariableIndices()
479
141
    );
480
141
    if (loopControl.kind == LoopControlKind::Break)
481
82
      brokeInCurrentIteration =
482
82
        brokeInCurrentIteration || loopControl.pathConditions;
483
59
    else if (loopControl.kind == LoopControlKind::Continue)
484
59
      continues = continues || loopControl.pathConditions;
485
141
  }
486
723
  return brokeInCurrentIteration;
487
723
}
488
489
bool BMC::visit(TryStatement const& _tryStatement)
490
146
{
491
146
  FunctionCall const* externalCall = dynamic_cast<FunctionCall const*>(&_tryStatement.externalCall());
492
146
  solAssert(externalCall && externalCall->annotation().tryCall, "");
493
494
146
  externalCall->accept(*this);
495
146
  if (_tryStatement.successClause()->parameters())
496
33
    expressionToTupleAssignment(_tryStatement.successClause()->parameters()->parameters(), *externalCall);
497
498
146
  smtutil::Expression clauseId = m_context.newVariable("clause_choice_" + std::to_string(m_context.newUniqueId()), smtutil::SortProvider::uintSort);
499
146
  auto const& clauses = _tryStatement.clauses();
500
146
  m_context.addAssertion(clauseId >= 0 && clauseId < clauses.size());
501
146
  solAssert(clauses[0].get() == _tryStatement.successClause(), "First clause of TryStatement should be the success clause");
502
146
  std::vector<std::pair<VariableIndices, smtutil::Expression>> clausesVisitResults;
503
444
  for (size_t i = 0; i < clauses.size(); ++i)
504
298
    clausesVisitResults.push_back(visitBranch(clauses[i].get()));
505
506
  // merge the information from all clauses
507
146
  smtutil::Expression pathCondition = clausesVisitResults.front().second;
508
146
  auto currentIndices = clausesVisitResults[0].first;
509
298
  for (size_t i = 1; i < clauses.size(); ++i)
510
152
  {
511
152
    mergeVariables(clauseId == i, clausesVisitResults[i].first, currentIndices);
512
152
    currentIndices = copyVariableIndices();
513
152
    pathCondition = pathCondition || clausesVisitResults[i].second;
514
152
  }
515
146
  setPathCondition(pathCondition);
516
517
146
  return false;
518
146
}
519
520
bool BMC::visit(Break const&)
521
82
{
522
82
  LoopControl control = {
523
82
    LoopControlKind::Break,
524
82
    currentPathConditions(),
525
82
    copyVariableIndices()
526
82
  };
527
82
  m_loopCheckpoints.top().emplace_back(control);
528
82
  return false;
529
82
}
530
531
bool BMC::visit(Continue const&)
532
59
{
533
59
  LoopControl control = {
534
59
    LoopControlKind::Continue,
535
59
    currentPathConditions(),
536
59
    copyVariableIndices()
537
59
  };
538
59
  m_loopCheckpoints.top().emplace_back(control);
539
59
  return false;
540
59
}
541
542
void BMC::endVisit(UnaryOperation const& _op)
543
4.88k
{
544
4.88k
  SMTEncoder::endVisit(_op);
545
546
  // User-defined operators are essentially function calls.
547
4.88k
  if (auto funDef = *_op.annotation().userDefinedFunction)
548
13
  {
549
13
    std::vector<Expression const*> arguments;
550
13
    arguments.push_back(&_op.subExpression());
551
    // pushCallStack and defineExpr inside createReturnedExpression should be called on the expression
552
    // in case of a user-defined operator call
553
13
    inlineFunctionCall(funDef, _op, std::nullopt, arguments);
554
13
    return;
555
13
  }
556
557
4.87k
  if (
558
4.87k
    _op.annotation().type->category() == Type::Category::RationalNumber ||
559
4.87k
    _op.annotation().type->category() == Type::Category::FixedPoint
560
4.87k
  )
561
1.29k
    return;
562
563
3.58k
  if (_op.getOperator() == Token::Sub && smt::isInteger(*_op.annotation().type))
564
161
  {
565
161
    addVerificationTarget(
566
161
      VerificationTargetType::Underflow,
567
161
      expr(_op),
568
161
      &_op
569
161
    );
570
161
    addVerificationTarget(
571
161
      VerificationTargetType::Overflow,
572
161
      expr(_op),
573
161
      &_op
574
161
    );
575
161
  }
576
3.58k
}
577
578
void BMC::endVisit(BinaryOperation const& _op)
579
25.1k
{
580
25.1k
  SMTEncoder::endVisit(_op);
581
582
25.1k
  if (auto funDef = *_op.annotation().userDefinedFunction)
583
33
  {
584
33
    std::vector<Expression const*> arguments;
585
33
    arguments.push_back(&_op.leftExpression());
586
33
    arguments.push_back(&_op.rightExpression());
587
588
    // pushCallStack and defineExpr inside createReturnedExpression should be called on the expression
589
    // in case of a user-defined operator call
590
33
    inlineFunctionCall(funDef, _op, std::nullopt, arguments);
591
33
  }
592
25.1k
}
593
594
void BMC::endVisit(FunctionCall const& _funCall)
595
16.1k
{
596
16.1k
  auto functionCallKind = *_funCall.annotation().kind;
597
598
16.1k
  if (functionCallKind != FunctionCallKind::FunctionCall)
599
3.04k
  {
600
3.04k
    SMTEncoder::endVisit(_funCall);
601
3.04k
    return;
602
3.04k
  }
603
604
13.1k
  FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
605
13.1k
  switch (funType.kind())
606
13.1k
  {
607
2.28k
  case FunctionType::Kind::Assert:
608
2.28k
    visitAssert(_funCall);
609
2.28k
    SMTEncoder::endVisit(_funCall);
610
2.28k
    break;
611
448
  case FunctionType::Kind::Require:
612
448
    visitRequire(_funCall);
613
448
    SMTEncoder::endVisit(_funCall);
614
448
    break;
615
2.00k
  case FunctionType::Kind::Internal:
616
2.90k
  case FunctionType::Kind::External:
617
3.11k
  case FunctionType::Kind::DelegateCall:
618
3.39k
  case FunctionType::Kind::BareCall:
619
3.39k
  case FunctionType::Kind::BareCallCode:
620
3.40k
  case FunctionType::Kind::BareDelegateCall:
621
3.41k
  case FunctionType::Kind::BareStaticCall:
622
3.72k
  case FunctionType::Kind::Creation:
623
3.72k
    SMTEncoder::endVisit(_funCall);
624
3.72k
    internalOrExternalFunctionCall(_funCall);
625
3.72k
    break;
626
17
  case FunctionType::Kind::Send:
627
110
  case FunctionType::Kind::Transfer:
628
110
  {
629
110
    auto value = _funCall.arguments().front();
630
110
    solAssert(value, "");
631
110
    smtutil::Expression thisBalance = state().balance();
632
633
110
    addVerificationTarget(
634
110
      VerificationTargetType::Balance,
635
110
      thisBalance < expr(*value),
636
110
      &_funCall
637
110
    );
638
639
110
    SMTEncoder::endVisit(_funCall);
640
110
    break;
641
110
  }
642
140
  case FunctionType::Kind::KECCAK256:
643
162
  case FunctionType::Kind::ECRecover:
644
179
  case FunctionType::Kind::SHA256:
645
286
  case FunctionType::Kind::RIPEMD160:
646
288
  case FunctionType::Kind::BlobHash:
647
316
  case FunctionType::Kind::BlockHash:
648
372
  case FunctionType::Kind::AddMod:
649
389
  case FunctionType::Kind::MulMod:
650
501
  case FunctionType::Kind::Unwrap:
651
697
  case FunctionType::Kind::Wrap:
652
697
    [[fallthrough]];
653
6.57k
  default:
654
6.57k
    SMTEncoder::endVisit(_funCall);
655
6.57k
    break;
656
13.1k
  }
657
13.1k
}
658
659
void BMC::endVisit(Return const& _return)
660
5.79k
{
661
5.79k
  SMTEncoder::endVisit(_return);
662
5.79k
  setPathCondition(smtutil::Expression(false));
663
5.79k
}
664
665
/// Visitor helpers.
666
667
void BMC::visitAssert(FunctionCall const& _funCall)
668
2.28k
{
669
2.28k
  auto const& args = _funCall.arguments();
670
2.28k
  solAssert(args.size() == 1, "");
671
2.28k
  solAssert(args.front()->annotation().type->category() == Type::Category::Bool, "");
672
2.28k
  addVerificationTarget(
673
2.28k
    VerificationTargetType::Assert,
674
2.28k
    expr(*args.front()),
675
2.28k
    &_funCall
676
2.28k
  );
677
2.28k
}
678
679
void BMC::visitRequire(FunctionCall const& _funCall)
680
448
{
681
448
  auto const& args = _funCall.arguments();
682
448
  solAssert(args.size() >= 1, "");
683
448
  solAssert(args.front()->annotation().type->category() == Type::Category::Bool, "");
684
448
  checkIfConditionIsConstant(*args.front());
685
448
}
686
687
void BMC::visitAddMulMod(FunctionCall const& _funCall)
688
73
{
689
73
  solAssert(_funCall.arguments().at(2), "");
690
73
  addVerificationTarget(
691
73
    VerificationTargetType::DivByZero,
692
73
    expr(*_funCall.arguments().at(2)),
693
73
    &_funCall
694
73
  );
695
696
73
  SMTEncoder::visitAddMulMod(_funCall);
697
73
}
698
699
void BMC::inlineFunctionCall(
700
  FunctionDefinition const* _funDef,
701
  Expression const& _callStackExpr,
702
  std::optional<Expression const*> _boundArgumentCall,
703
  std::vector<Expression const*> const& _arguments
704
)
705
2.27k
{
706
2.27k
  solAssert(_funDef, "");
707
708
2.27k
  if (visitedFunction(_funDef))
709
345
  {
710
345
    auto const& returnParams = _funDef->returnParameters();
711
345
    for (auto param: returnParams)
712
355
    {
713
355
      m_context.newValue(*param);
714
355
      m_context.setUnknownValue(*param);
715
355
    }
716
345
  }
717
1.93k
  else
718
1.93k
  {
719
1.93k
    initializeFunctionCallParameters(*_funDef, symbolicArguments(_funDef->parameters(), _arguments, _boundArgumentCall));
720
721
    // The reason why we need to pushCallStack here instead of visit(FunctionDefinition)
722
    // is that there we don't have `_callStackExpr`.
723
1.93k
    pushCallStack({_funDef, &_callStackExpr});
724
1.93k
    pushPathCondition(currentPathConditions());
725
1.93k
    auto oldChecked = std::exchange(m_checked, true);
726
1.93k
    _funDef->accept(*this);
727
1.93k
    m_checked = oldChecked;
728
1.93k
    popPathCondition();
729
1.93k
  }
730
731
2.27k
  createReturnedExpressions(_funDef, _callStackExpr);
732
2.27k
}
733
734
void BMC::inlineFunctionCall(FunctionCall const& _funCall)
735
2.23k
{
736
2.23k
  solAssert(shouldInlineFunctionCall(_funCall, currentScopeContract(), m_currentContract), "");
737
738
2.23k
  auto funDef = functionCallToDefinition(_funCall, currentScopeContract(), m_currentContract);
739
2.23k
  Expression const* expr = &_funCall.expression();
740
2.23k
  auto funType = dynamic_cast<FunctionType const*>(expr->annotation().type);
741
2.23k
  std::optional<Expression const*> boundArgumentCall =
742
2.23k
    funType->hasBoundFirstArgument() ? std::make_optional(expr) : std::nullopt;
743
744
2.23k
  std::vector<Expression const*> arguments;
745
2.23k
  for (auto& arg: _funCall.sortedArguments())
746
1.04k
    arguments.push_back(&(*arg));
747
748
  // pushCallStack and defineExpr inside createReturnedExpression should be called
749
  // on the FunctionCall object for the normal function call case
750
2.23k
  inlineFunctionCall(funDef, _funCall, boundArgumentCall, arguments);
751
2.23k
}
752
753
void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall)
754
3.72k
{
755
3.72k
  auto const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
756
3.72k
  if (shouldInlineFunctionCall(_funCall, currentScopeContract(), m_currentContract))
757
2.23k
    inlineFunctionCall(_funCall);
758
1.49k
  else if (publicGetter(_funCall.expression()))
759
187
  {
760
    // Do nothing here.
761
    // The processing happens in SMT Encoder, but we need to prevent the resetting of the state variables.
762
187
  }
763
1.30k
  else if (funType.kind() == FunctionType::Kind::Internal)
764
134
    m_unsupportedErrors.warning(
765
134
      5729_error,
766
134
      _funCall.location(),
767
134
      "BMC does not yet implement this type of function call."
768
134
    );
769
1.17k
  else if (funType.kind() == FunctionType::Kind::BareStaticCall)
770
14
  {
771
    // Do nothing here.
772
    // Neither storage nor balances should be modified.
773
14
  }
774
1.16k
  else
775
1.16k
  {
776
1.16k
    m_externalFunctionCallHappened = true;
777
1.16k
    resetStorageVariables();
778
1.16k
    resetBalances();
779
1.16k
  }
780
3.72k
}
781
782
std::pair<smtutil::Expression, smtutil::Expression> BMC::arithmeticOperation(
783
  Token _op,
784
  smtutil::Expression const& _left,
785
  smtutil::Expression const& _right,
786
  Type const* _commonType,
787
  Expression const& _expression
788
)
789
14.1k
{
790
  // Unchecked does not disable div by 0 checks.
791
14.1k
  if (_op == Token::Div || _op == Token::Mod)
792
1.17k
    addVerificationTarget(
793
1.17k
      VerificationTargetType::DivByZero,
794
1.17k
      _right,
795
1.17k
      &_expression
796
1.17k
    );
797
798
14.1k
  auto values = SMTEncoder::arithmeticOperation(_op, _left, _right, _commonType, _expression);
799
800
14.1k
  if (!m_checked)
801
136
    return values;
802
803
14.0k
  auto const* intType = dynamic_cast<IntegerType const*>(_commonType);
804
14.0k
  if (!intType)
805
220
    intType = TypeProvider::uint256();
806
807
  // Mod does not need underflow/overflow checks.
808
14.0k
  if (_op == Token::Mod)
809
505
    return values;
810
811
  // The order matters here:
812
  // If _op is Div and intType is signed, we only care about overflow.
813
13.5k
  if (_op == Token::Div)
814
662
  {
815
662
    if (intType->isSigned())
816
      // Signed division can only overflow.
817
76
      addVerificationTarget(VerificationTargetType::Overflow, values.second, &_expression);
818
586
    else
819
      // Unsigned division cannot underflow/overflow.
820
586
      return values;
821
662
  }
822
12.8k
  else if (intType->isSigned())
823
689
  {
824
689
    addVerificationTarget(VerificationTargetType::Overflow, values.second, &_expression);
825
689
    addVerificationTarget(VerificationTargetType::Underflow, values.second, &_expression);
826
689
  }
827
12.1k
  else if (_op == Token::Sub)
828
5.52k
    addVerificationTarget(VerificationTargetType::Underflow, values.second, &_expression);
829
6.64k
  else if (_op == Token::Add || _op == Token::Mul)
830
6.64k
    addVerificationTarget(VerificationTargetType::Overflow, values.second, &_expression);
831
0
  else
832
6.64k
    solAssert(false, "");
833
834
12.9k
  return values;
835
13.5k
}
836
837
void BMC::reset()
838
17.0k
{
839
17.0k
  m_externalFunctionCallHappened = false;
840
17.0k
  m_loopExecutionHappened = false;
841
17.0k
}
842
843
std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> BMC::modelExpressions()
844
3.63k
{
845
3.63k
  std::vector<smtutil::Expression> expressionsToEvaluate;
846
3.63k
  std::vector<std::string> expressionNames;
847
3.63k
  for (auto const& var: m_context.variables())
848
8.82k
    if (var.first->type()->isValueType())
849
6.52k
    {
850
6.52k
      expressionsToEvaluate.emplace_back(currentValue(*var.first));
851
6.52k
      expressionNames.push_back(var.first->name());
852
6.52k
    }
853
3.63k
  for (auto const& var: m_context.globalSymbols())
854
340
  {
855
340
    auto const& type = var.second->type();
856
340
    if (
857
340
      type->isValueType() &&
858
340
      smt::smtKind(*type) != smtutil::Kind::Function
859
340
    )
860
20
    {
861
20
      expressionsToEvaluate.emplace_back(var.second->currentValue());
862
20
      expressionNames.push_back(var.first);
863
20
    }
864
340
  }
865
3.63k
  for (auto const& uf: m_uninterpretedTerms)
866
9.99k
    if (uf->annotation().type->isValueType())
867
6.14k
    {
868
6.14k
      expressionsToEvaluate.emplace_back(expr(*uf));
869
6.14k
      std::string expressionName;
870
6.14k
      if (uf->location().hasText())
871
6.14k
        expressionName = m_charStreamProvider.charStream(*uf->location().sourceName).text(
872
6.14k
          uf->location()
873
6.14k
        );
874
6.14k
      expressionNames.push_back(std::move(expressionName));
875
6.14k
    }
876
877
3.63k
  return {expressionsToEvaluate, expressionNames};
878
3.63k
}
879
880
/// Verification targets.
881
882
std::string BMC::targetDescription(BMCVerificationTarget const& _target)
883
0
{
884
0
  if (
885
0
    _target.type == VerificationTargetType::Underflow ||
886
0
    _target.type == VerificationTargetType::Overflow
887
0
  )
888
0
  {
889
0
    auto const* intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type);
890
0
    if (!intType)
891
0
      intType = TypeProvider::uint256();
892
893
0
    if (_target.type == VerificationTargetType::Underflow)
894
0
      return "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")";
895
0
    return "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")";
896
0
  }
897
0
  else if (_target.type == VerificationTargetType::DivByZero)
898
0
    return "Division by zero";
899
0
  else if (_target.type == VerificationTargetType::Assert)
900
0
    return "Assertion violation";
901
0
  else if (_target.type == VerificationTargetType::Balance)
902
0
    return "Insufficient funds";
903
0
  solAssert(false);
904
0
}
905
906
void BMC::checkVerificationTargets()
907
32.8k
{
908
32.8k
  for (auto& target: m_verificationTargets)
909
3.62k
    checkVerificationTarget(target);
910
32.8k
}
911
912
void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
913
3.62k
{
914
3.62k
  if (
915
3.62k
    m_solvedTargets.count(_target.expression) &&
916
3.62k
    m_solvedTargets.at(_target.expression).count(_target.type)
917
3.62k
  )
918
33
    return;
919
920
3.58k
  switch (_target.type)
921
3.58k
  {
922
0
    case VerificationTargetType::Underflow:
923
0
      checkUnderflow(_target);
924
0
      break;
925
0
    case VerificationTargetType::Overflow:
926
0
      checkOverflow(_target);
927
0
      break;
928
1.22k
    case VerificationTargetType::DivByZero:
929
1.22k
      checkDivByZero(_target);
930
1.22k
      break;
931
107
    case VerificationTargetType::Balance:
932
107
      checkBalance(_target);
933
107
      break;
934
2.25k
    case VerificationTargetType::Assert:
935
2.25k
      checkAssert(_target);
936
2.25k
      break;
937
0
    case VerificationTargetType::ConstantCondition:
938
0
      smtAssert(false, "Checks for constant condition are handled separately");
939
0
    default:
940
0
      smtAssert(false);
941
3.58k
  }
942
3.58k
}
943
944
void BMC::checkIfConditionIsConstant(Expression const& _condition)
945
1.88k
{
946
1.88k
  if (
947
1.88k
    !m_settings.targets.has(VerificationTargetType::ConstantCondition) ||
948
1.88k
    (m_currentContract && !shouldEncode(*m_currentContract))
949
1.88k
  )
950
15
    return;
951
952
  // We ignore called functions here because they have specific input values.
953
  // Also, expressions inside loop can have different values in different iterations.
954
1.86k
  if (!isRootFunction() || isInsideLoop())
955
394
    return;
956
957
  // Do not check for const-ness if this is a literal.
958
1.47k
  if (dynamic_cast<Literal const*>(&_condition))
959
77
    return;
960
961
1.39k
  auto [canBeTrue, canBeFalse] = checkBooleanNotConstant(currentPathConditions() && m_context.assertions(), expr(_condition));
962
963
  // Report based on the result of the checks
964
1.39k
  if (canBeTrue == CheckResult::ERROR || canBeFalse == CheckResult::ERROR)
965
0
    m_errorReporter.warning(8592_error, _condition.location(), "BMC: Error trying to invoke SMT solver.");
966
1.39k
  else if (canBeTrue == CheckResult::CONFLICTING || canBeFalse == CheckResult::CONFLICTING)
967
0
    m_errorReporter.warning(3356_error, _condition.location(), "BMC: At least two SMT solvers provided conflicting answers. Results might not be sound.");
968
1.39k
  else if (canBeTrue == CheckResult::UNKNOWN || canBeFalse == CheckResult::UNKNOWN)
969
1.39k
  {
970
    // Not enough information to make definite claims.
971
1.39k
  }
972
0
  else if (canBeTrue == CheckResult::SATISFIABLE && canBeFalse == CheckResult::SATISFIABLE)
973
0
  {
974
    // Condition can be both true and false for some program runs.
975
0
  }
976
977
0
  else if (canBeTrue == CheckResult::UNSATISFIABLE && canBeFalse == CheckResult::UNSATISFIABLE)
978
0
    m_errorReporter.warning(2512_error, _condition.location(), "BMC: Condition unreachable.", SMTEncoder::callStackMessage(m_callStack));
979
0
  else
980
0
  {
981
0
    std::string description;
982
0
    if (canBeFalse == smtutil::CheckResult::UNSATISFIABLE)
983
0
    {
984
0
      smtAssert(canBeTrue == smtutil::CheckResult::SATISFIABLE);
985
0
      description = "BMC: Condition is always true.";
986
0
    }
987
0
    else
988
0
    {
989
0
      smtAssert(canBeTrue == smtutil::CheckResult::UNSATISFIABLE);
990
0
      smtAssert(canBeFalse == smtutil::CheckResult::SATISFIABLE);
991
0
      description = "BMC: Condition is always false.";
992
0
    }
993
0
    m_errorReporter.warning(
994
0
      6838_error,
995
0
      _condition.location(),
996
0
      description,
997
0
      SMTEncoder::callStackMessage(m_callStack)
998
0
    );
999
0
  }
1000
1001
1.39k
}
1002
1003
void BMC::checkUnderflow(BMCVerificationTarget& _target)
1004
0
{
1005
0
  solAssert(
1006
0
    _target.type == VerificationTargetType::Underflow,
1007
0
    ""
1008
0
  );
1009
1010
0
  auto const* intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type);
1011
0
  if (!intType)
1012
0
    intType = TypeProvider::uint256();
1013
1014
0
  checkCondition(
1015
0
    _target,
1016
0
    _target.constraints && _target.value < smt::minValue(*intType),
1017
0
    _target.callStack,
1018
0
    _target.modelExpressions,
1019
0
    _target.expression->location(),
1020
0
    4144_error,
1021
0
    8312_error,
1022
0
    "<result>",
1023
0
    &_target.value
1024
0
  );
1025
0
}
1026
1027
void BMC::checkOverflow(BMCVerificationTarget& _target)
1028
0
{
1029
0
  solAssert(
1030
0
    _target.type == VerificationTargetType::Overflow,
1031
0
    ""
1032
0
  );
1033
1034
0
  auto const* intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type);
1035
0
  if (!intType)
1036
0
    intType = TypeProvider::uint256();
1037
1038
0
  checkCondition(
1039
0
    _target,
1040
0
    _target.constraints && _target.value > smt::maxValue(*intType),
1041
0
    _target.callStack,
1042
0
    _target.modelExpressions,
1043
0
    _target.expression->location(),
1044
0
    2661_error,
1045
0
    8065_error,
1046
0
    "<result>",
1047
0
    &_target.value
1048
0
  );
1049
0
}
1050
1051
void BMC::checkDivByZero(BMCVerificationTarget& _target)
1052
1.22k
{
1053
1.22k
  solAssert(_target.type == VerificationTargetType::DivByZero, "");
1054
1055
1.22k
  checkCondition(
1056
1.22k
    _target,
1057
1.22k
    _target.constraints && (_target.value == 0),
1058
1.22k
    _target.callStack,
1059
1.22k
    _target.modelExpressions,
1060
1.22k
    _target.expression->location(),
1061
1.22k
    3046_error,
1062
1.22k
    5272_error,
1063
1.22k
    "<result>",
1064
1.22k
    &_target.value
1065
1.22k
  );
1066
1.22k
}
1067
1068
void BMC::checkBalance(BMCVerificationTarget& _target)
1069
107
{
1070
107
  solAssert(_target.type == VerificationTargetType::Balance, "");
1071
1072
107
  checkCondition(
1073
107
    _target,
1074
107
    _target.constraints && _target.value,
1075
107
    _target.callStack,
1076
107
    _target.modelExpressions,
1077
107
    _target.expression->location(),
1078
107
    1236_error,
1079
107
    4010_error,
1080
107
    "address(this).balance"
1081
107
  );
1082
107
}
1083
1084
void BMC::checkAssert(BMCVerificationTarget& _target)
1085
2.25k
{
1086
2.25k
  solAssert(_target.type == VerificationTargetType::Assert, "");
1087
1088
2.25k
  checkCondition(
1089
2.25k
    _target,
1090
2.25k
    _target.constraints && !_target.value,
1091
2.25k
    _target.callStack,
1092
2.25k
    _target.modelExpressions,
1093
2.25k
    _target.expression->location(),
1094
2.25k
    4661_error,
1095
2.25k
    7812_error
1096
2.25k
  );
1097
2.25k
}
1098
1099
void BMC::addVerificationTarget(
1100
  VerificationTargetType _type,
1101
  smtutil::Expression const& _value,
1102
  Expression const* _expression
1103
)
1104
17.5k
{
1105
17.5k
  smtAssert(_type != VerificationTargetType::ConstantCondition, "Checks for constant condition are handled separately");
1106
17.5k
  if (!m_settings.targets.has(_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor(*m_currentContract)))
1107
13.9k
    return;
1108
1109
3.63k
  BMCVerificationTarget target{
1110
3.63k
    {
1111
3.63k
      _type,
1112
3.63k
      _value,
1113
3.63k
      currentPathConditions() && m_context.assertions()
1114
3.63k
    },
1115
3.63k
    _expression,
1116
3.63k
    m_callStack,
1117
3.63k
    modelExpressions()
1118
3.63k
  };
1119
3.63k
  m_verificationTargets.emplace_back(std::move(target));
1120
3.63k
}
1121
1122
/// Solving.
1123
1124
void BMC::checkCondition(
1125
  BMCVerificationTarget const& _target,
1126
  smtutil::Expression _condition,
1127
  std::vector<SMTEncoder::CallStackEntry> const& _callStack,
1128
  std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> const& _modelExpressions,
1129
  SourceLocation const& _location,
1130
  ErrorId _errorHappens,
1131
  ErrorId _errorMightHappen,
1132
  std::string const& _additionalValueName,
1133
  smtutil::Expression const* _additionalValue
1134
)
1135
3.58k
{
1136
3.58k
  m_interface->push();
1137
3.58k
  m_interface->addAssertion(_condition);
1138
1139
3.58k
  std::vector<smtutil::Expression> expressionsToEvaluate;
1140
3.58k
  std::vector<std::string> expressionNames;
1141
3.58k
  tie(expressionsToEvaluate, expressionNames) = _modelExpressions;
1142
3.58k
  if (!_callStack.empty())
1143
3.58k
    if (_additionalValue)
1144
1.22k
    {
1145
1.22k
      expressionsToEvaluate.emplace_back(*_additionalValue);
1146
1.22k
      expressionNames.push_back(_additionalValueName);
1147
1.22k
    }
1148
3.58k
  smtutil::CheckResult result;
1149
3.58k
  std::vector<std::string> values;
1150
3.58k
  tie(result, values) = checkSatisfiableAndGenerateModel(expressionsToEvaluate);
1151
1152
3.58k
  std::string extraComment = SMTEncoder::extraComment();
1153
3.58k
  if (m_loopExecutionHappened)
1154
98
    extraComment +=
1155
98
      "False negatives are possible when unrolling loops.\n"
1156
98
      "This is due to the possibility that the BMC loop iteration setting is"
1157
98
      " smaller than the actual number of iterations needed to complete a loop.";
1158
3.58k
  if (m_externalFunctionCallHappened)
1159
86
    extraComment +=
1160
86
      "\nNote that external function calls are not inlined,"
1161
86
      " even if the source code of the function is available."
1162
86
      " This is due to the possibility that the actual called contract"
1163
86
      " has the same ABI but implements the function differently.";
1164
1165
3.58k
  SecondarySourceLocation secondaryLocation{};
1166
3.58k
  secondaryLocation.append(extraComment, SourceLocation{});
1167
1168
3.58k
  switch (result)
1169
3.58k
  {
1170
0
  case smtutil::CheckResult::SATISFIABLE:
1171
0
  {
1172
0
    solAssert(!_callStack.empty(), "");
1173
0
    std::ostringstream message;
1174
0
    message << "BMC: " << targetDescription(_target) << " happens here.";
1175
1176
0
    std::ostringstream modelMessage;
1177
    // Sometimes models have complex smtlib2 expressions that SMTLib2Interface fails to parse.
1178
0
    if (values.size() == expressionNames.size())
1179
0
    {
1180
0
      modelMessage << "Counterexample:\n";
1181
0
      std::map<std::string, std::string> sortedModel;
1182
0
      for (size_t i = 0; i < values.size(); ++i)
1183
0
        if (expressionsToEvaluate.at(i).name != values.at(i))
1184
0
          sortedModel[expressionNames.at(i)] = values.at(i);
1185
1186
0
      for (auto const& eval: sortedModel)
1187
0
        modelMessage << "  " << eval.first << " = " << eval.second << "\n";
1188
0
    }
1189
1190
0
    m_errorReporter.warning(
1191
0
      _errorHappens,
1192
0
      _location,
1193
0
      message.str(),
1194
0
      SecondarySourceLocation().append(modelMessage.str(), SourceLocation{})
1195
0
      .append(SMTEncoder::callStackMessage(_callStack))
1196
0
      .append(std::move(secondaryLocation))
1197
0
    );
1198
0
    break;
1199
0
  }
1200
0
  case smtutil::CheckResult::UNSATISFIABLE:
1201
0
  {
1202
0
    m_safeTargets[_target.expression].insert(_target);
1203
0
    break;
1204
0
  }
1205
3.58k
  case smtutil::CheckResult::UNKNOWN:
1206
3.58k
  {
1207
3.58k
    ++m_unprovedAmt;
1208
3.58k
    if (m_settings.showUnproved)
1209
0
      m_errorReporter.warning(_errorMightHappen, _location, "BMC: " + targetDescription(_target) + " might happen here.", secondaryLocation);
1210
3.58k
    break;
1211
0
  }
1212
0
  case smtutil::CheckResult::CONFLICTING:
1213
0
    m_errorReporter.warning(1584_error, _location, "BMC: At least two SMT solvers provided conflicting answers. Results might not be sound.");
1214
0
    break;
1215
0
  case smtutil::CheckResult::ERROR:
1216
0
    m_errorReporter.warning(1823_error, _location, "BMC: Error during interaction with the SMT solver.");
1217
0
    break;
1218
3.58k
  }
1219
1220
3.58k
  m_interface->pop();
1221
3.58k
}
1222
1223
BMC::ConstantExpressionCheckResult BMC::checkBooleanNotConstant(
1224
  smtutil::Expression const& _constraints,
1225
  smtutil::Expression const& _condition
1226
)
1227
1.39k
{
1228
1.39k
  m_interface->push();
1229
1.39k
  m_interface->addAssertion(_constraints && _condition);
1230
1.39k
  auto positiveResult = checkSatisfiable();
1231
1.39k
  m_interface->pop();
1232
1233
1.39k
  m_interface->push();
1234
1.39k
  m_interface->addAssertion(_constraints && !_condition);
1235
1.39k
  auto negatedResult = checkSatisfiable();
1236
1.39k
  m_interface->pop();
1237
1238
1.39k
  return {.canBeTrue = positiveResult, .canBeFalse = negatedResult};
1239
1.39k
}
1240
1241
std::pair<smtutil::CheckResult, std::vector<std::string>>
1242
BMC::checkSatisfiableAndGenerateModel(std::vector<smtutil::Expression> const& _expressionsToEvaluate)
1243
6.37k
{
1244
6.37k
  smtutil::CheckResult result;
1245
6.37k
  std::vector<std::string> values;
1246
6.37k
  try
1247
6.37k
  {
1248
6.37k
    if (m_settings.printQuery)
1249
0
    {
1250
0
      auto portfolio = dynamic_cast<smtutil::SMTPortfolio*>(m_interface.get());
1251
0
      std::string smtlibCode = portfolio->dumpQuery(_expressionsToEvaluate);
1252
0
      m_errorReporter.info(
1253
0
        6240_error,
1254
0
        "BMC: Requested query:\n" + smtlibCode
1255
0
      );
1256
0
      result = CheckResult::UNKNOWN;
1257
0
    }
1258
6.37k
    else
1259
6.37k
      tie(result, values) = m_interface->check(_expressionsToEvaluate);
1260
6.37k
  }
1261
6.37k
  catch (smtutil::SolverError const& _e)
1262
6.37k
  {
1263
0
    std::string description("BMC: Error querying SMT solver");
1264
0
    if (_e.comment())
1265
0
      description += ": " + *_e.comment();
1266
0
    m_errorReporter.warning(8140_error, description);
1267
0
    result = smtutil::CheckResult::ERROR;
1268
0
  }
1269
1270
6.37k
  for (std::string& value: values)
1271
0
  {
1272
0
    try
1273
0
    {
1274
      // Parse and re-format nicely
1275
0
      value = formatNumberReadable(bigint(value));
1276
0
    }
1277
0
    catch (...) { }
1278
0
  }
1279
1280
6.37k
  return make_pair(result, values);
1281
6.37k
}
1282
1283
smtutil::CheckResult BMC::checkSatisfiable()
1284
2.79k
{
1285
2.79k
  return checkSatisfiableAndGenerateModel({}).first;
1286
2.79k
}
1287
1288
void BMC::assignment(smt::SymbolicVariable& _symVar, smtutil::Expression const& _value)
1289
26.8k
{
1290
26.8k
  auto oldVar = _symVar.currentValue();
1291
26.8k
  auto newVar = _symVar.increaseIndex();
1292
26.8k
  m_context.addAssertion(smtutil::Expression::ite(
1293
26.8k
    currentPathConditions(),
1294
26.8k
    newVar == _value,
1295
26.8k
    newVar == oldVar
1296
26.8k
  ));
1297
26.8k
}
1298
1299
bool BMC::isInsideLoop() const
1300
1.62k
{
1301
1.62k
  return !m_loopCheckpoints.empty();
1302
1.62k
}