Coverage Report

Created: 2022-08-24 06:38

/src/solidity/libsmtutil/SolverInterface.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 <libsmtutil/Exceptions.h>
22
#include <libsmtutil/Sorts.h>
23
24
#include <libsolutil/Common.h>
25
#include <libsolutil/Numeric.h>
26
#include <libsolutil/CommonData.h>
27
28
#include <range/v3/algorithm/all_of.hpp>
29
#include <range/v3/view.hpp>
30
31
#include <cstdio>
32
#include <map>
33
#include <memory>
34
#include <optional>
35
#include <set>
36
#include <string>
37
#include <vector>
38
39
namespace solidity::smtutil
40
{
41
42
struct SMTSolverChoice
43
{
44
  bool cvc4 = false;
45
  bool smtlib2 = false;
46
  bool z3 = false;
47
48
0
  static constexpr SMTSolverChoice All() noexcept { return {true, true, true}; }
49
0
  static constexpr SMTSolverChoice CVC4() noexcept { return {true, false, false}; }
50
0
  static constexpr SMTSolverChoice SMTLIB2() noexcept { return {false, true, false}; }
51
0
  static constexpr SMTSolverChoice Z3() noexcept { return {false, false, true}; }
52
0
  static constexpr SMTSolverChoice None() noexcept { return {false, false, false}; }
53
54
  static std::optional<SMTSolverChoice> fromString(std::string const& _solvers)
55
0
  {
56
0
    SMTSolverChoice solvers;
57
0
    if (_solvers == "all")
58
0
    {
59
0
      smtAssert(solvers.setSolver("cvc4"), "");
60
0
      smtAssert(solvers.setSolver("smtlib2"), "");
61
0
      smtAssert(solvers.setSolver("z3"), "");
62
0
    }
63
0
    else
64
0
      for (auto&& s: _solvers | ranges::views::split(',') | ranges::to<std::vector<std::string>>())
65
0
        if (!solvers.setSolver(s))
66
0
          return {};
67
0
68
0
    return solvers;
69
0
  }
70
71
  SMTSolverChoice& operator&=(SMTSolverChoice const& _other)
72
0
  {
73
0
    cvc4 &= _other.cvc4;
74
0
    smtlib2 &= _other.smtlib2;
75
0
    z3 &= _other.z3;
76
0
    return *this;
77
0
  }
78
79
  SMTSolverChoice operator&(SMTSolverChoice _other) const noexcept
80
0
  {
81
0
    _other &= *this;
82
0
    return _other;
83
0
  }
84
85
0
  bool operator!=(SMTSolverChoice const& _other) const noexcept { return !(*this == _other); }
86
87
  bool operator==(SMTSolverChoice const& _other) const noexcept
88
0
  {
89
0
    return cvc4 == _other.cvc4 &&
90
0
      smtlib2 == _other.smtlib2 &&
91
0
      z3 == _other.z3;
92
0
  }
93
94
  bool setSolver(std::string const& _solver)
95
0
  {
96
0
    static std::set<std::string> const solvers{"cvc4", "smtlib2", "z3"};
97
0
    if (!solvers.count(_solver))
98
0
      return false;
99
0
    if (_solver == "cvc4")
100
0
      cvc4 = true;
101
0
    else if (_solver == "smtlib2")
102
0
      smtlib2 = true;
103
0
    else if (_solver == "z3")
104
0
      z3 = true;
105
0
    return true;
106
0
  }
107
108
0
  bool none() const noexcept { return !some(); }
109
0
  bool some() const noexcept { return cvc4 || smtlib2 || z3; }
110
0
  bool all() const noexcept { return cvc4 && smtlib2 && z3; }
111
};
112
113
enum class CheckResult
114
{
115
  SATISFIABLE, UNSATISFIABLE, UNKNOWN, CONFLICTING, ERROR
116
};
117
118
/// C++ representation of an SMTLIB2 expression.
119
class Expression
120
{
121
  friend class SolverInterface;
122
public:
123
0
  explicit Expression(bool _v): Expression(_v ? "true" : "false", Kind::Bool) {}
124
0
  explicit Expression(std::shared_ptr<SortSort> _sort, std::string _name = ""): Expression(std::move(_name), {}, _sort) {}
125
  explicit Expression(std::string _name, std::vector<Expression> _arguments, SortPointer _sort):
126
0
    name(std::move(_name)), arguments(std::move(_arguments)), sort(std::move(_sort)) {}
127
0
  Expression(size_t _number): Expression(std::to_string(_number), {}, SortProvider::sintSort) {}
128
0
  Expression(u256 const& _number): Expression(_number.str(), {}, SortProvider::sintSort) {}
129
  Expression(s256 const& _number): Expression(
130
    _number >= 0 ? _number.str() : "-",
131
    _number >= 0 ?
132
      std::vector<Expression>{} :
133
      std::vector<Expression>{Expression(size_t(0)), bigint(-_number)},
134
    SortProvider::sintSort
135
0
  ) {}
136
  Expression(bigint const& _number): Expression(
137
    _number >= 0 ? _number.str() : "-",
138
    _number >= 0 ?
139
      std::vector<Expression>{} :
140
      std::vector<Expression>{Expression(size_t(0)), bigint(-_number)},
141
    SortProvider::sintSort
142
0
  ) {}
143
144
0
  Expression(Expression const&) = default;
145
0
  Expression(Expression&&) = default;
146
  Expression& operator=(Expression const&) = default;
147
0
  Expression& operator=(Expression&&) = default;
148
149
  bool hasCorrectArity() const
150
0
  {
151
0
    if (name == "tuple_constructor")
152
0
    {
153
0
      auto tupleSort = std::dynamic_pointer_cast<TupleSort>(sort);
154
0
      smtAssert(tupleSort, "");
155
0
      return arguments.size() == tupleSort->components.size();
156
0
    }
157
0
158
0
    static std::map<std::string, unsigned> const operatorsArity{
159
0
      {"ite", 3},
160
0
      {"not", 1},
161
0
      {"and", 2},
162
0
      {"or", 2},
163
0
      {"=>", 2},
164
0
      {"=", 2},
165
0
      {"<", 2},
166
0
      {"<=", 2},
167
0
      {">", 2},
168
0
      {">=", 2},
169
0
      {"+", 2},
170
0
      {"-", 2},
171
0
      {"*", 2},
172
0
      {"div", 2},
173
0
      {"mod", 2},
174
0
      {"bvnot", 1},
175
0
      {"bvand", 2},
176
0
      {"bvor", 2},
177
0
      {"bvxor", 2},
178
0
      {"bvshl", 2},
179
0
      {"bvlshr", 2},
180
0
      {"bvashr", 2},
181
0
      {"int2bv", 2},
182
0
      {"bv2int", 1},
183
0
      {"select", 2},
184
0
      {"store", 3},
185
0
      {"const_array", 2},
186
0
      {"tuple_get", 2}
187
0
    };
188
0
    return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
189
0
  }
190
191
  static Expression ite(Expression _condition, Expression _trueValue, Expression _falseValue)
192
0
  {
193
0
    smtAssert(*_trueValue.sort == *_falseValue.sort, "");
194
0
    SortPointer sort = _trueValue.sort;
195
0
    return Expression("ite", std::vector<Expression>{
196
0
      std::move(_condition), std::move(_trueValue), std::move(_falseValue)
197
0
    }, std::move(sort));
198
0
  }
199
200
  static Expression implies(Expression _a, Expression _b)
201
0
  {
202
0
    return Expression(
203
0
      "=>",
204
0
      std::move(_a),
205
0
      std::move(_b),
206
0
      Kind::Bool
207
0
    );
208
0
  }
209
210
  /// select is the SMT representation of an array index access.
211
  static Expression select(Expression _array, Expression _index)
212
0
  {
213
0
    smtAssert(_array.sort->kind == Kind::Array, "");
214
0
    std::shared_ptr<ArraySort> arraySort = std::dynamic_pointer_cast<ArraySort>(_array.sort);
215
0
    smtAssert(arraySort, "");
216
0
    smtAssert(_index.sort, "");
217
0
    smtAssert(*arraySort->domain == *_index.sort, "");
218
0
    return Expression(
219
0
      "select",
220
0
      std::vector<Expression>{std::move(_array), std::move(_index)},
221
0
      arraySort->range
222
0
    );
223
0
  }
224
225
  /// store is the SMT representation of an assignment to array index.
226
  /// The function is pure and returns the modified array.
227
  static Expression store(Expression _array, Expression _index, Expression _element)
228
0
  {
229
0
    auto arraySort = std::dynamic_pointer_cast<ArraySort>(_array.sort);
230
0
    smtAssert(arraySort, "");
231
0
    smtAssert(_index.sort, "");
232
0
    smtAssert(_element.sort, "");
233
0
    smtAssert(*arraySort->domain == *_index.sort, "");
234
0
    smtAssert(*arraySort->range == *_element.sort, "");
235
0
    return Expression(
236
0
      "store",
237
0
      std::vector<Expression>{std::move(_array), std::move(_index), std::move(_element)},
238
0
      arraySort
239
0
    );
240
0
  }
241
242
  static Expression const_array(Expression _sort, Expression _value)
243
0
  {
244
0
    smtAssert(_sort.sort->kind == Kind::Sort, "");
245
0
    auto sortSort = std::dynamic_pointer_cast<SortSort>(_sort.sort);
246
0
    auto arraySort = std::dynamic_pointer_cast<ArraySort>(sortSort->inner);
247
0
    smtAssert(sortSort && arraySort, "");
248
0
    smtAssert(_value.sort, "");
249
0
    smtAssert(*arraySort->range == *_value.sort, "");
250
0
    return Expression(
251
0
      "const_array",
252
0
      std::vector<Expression>{std::move(_sort), std::move(_value)},
253
0
      arraySort
254
0
    );
255
0
  }
256
257
  static Expression tuple_get(Expression _tuple, size_t _index)
258
0
  {
259
0
    smtAssert(_tuple.sort->kind == Kind::Tuple, "");
260
0
    std::shared_ptr<TupleSort> tupleSort = std::dynamic_pointer_cast<TupleSort>(_tuple.sort);
261
0
    smtAssert(tupleSort, "");
262
0
    smtAssert(_index < tupleSort->components.size(), "");
263
0
    return Expression(
264
0
      "tuple_get",
265
0
      std::vector<Expression>{std::move(_tuple), Expression(_index)},
266
0
      tupleSort->components.at(_index)
267
0
    );
268
0
  }
269
270
  static Expression tuple_constructor(Expression _tuple, std::vector<Expression> _arguments)
271
0
  {
272
0
    smtAssert(_tuple.sort->kind == Kind::Sort, "");
273
0
    auto sortSort = std::dynamic_pointer_cast<SortSort>(_tuple.sort);
274
0
    auto tupleSort = std::dynamic_pointer_cast<TupleSort>(sortSort->inner);
275
0
    smtAssert(tupleSort, "");
276
0
    smtAssert(_arguments.size() == tupleSort->components.size(), "");
277
0
    return Expression(
278
0
      "tuple_constructor",
279
0
      std::move(_arguments),
280
0
      tupleSort
281
0
    );
282
0
  }
283
284
  static Expression int2bv(Expression _n, size_t _size)
285
0
  {
286
0
    smtAssert(_n.sort->kind == Kind::Int, "");
287
0
    std::shared_ptr<IntSort> intSort = std::dynamic_pointer_cast<IntSort>(_n.sort);
288
0
    smtAssert(intSort, "");
289
0
    smtAssert(_size <= 256, "");
290
0
    return Expression(
291
0
      "int2bv",
292
0
      std::vector<Expression>{std::move(_n), Expression(_size)},
293
0
      std::make_shared<BitVectorSort>(_size)
294
0
    );
295
0
  }
296
297
  static Expression bv2int(Expression _bv, bool _signed = false)
298
0
  {
299
0
    smtAssert(_bv.sort->kind == Kind::BitVector, "");
300
0
    std::shared_ptr<BitVectorSort> bvSort = std::dynamic_pointer_cast<BitVectorSort>(_bv.sort);
301
0
    smtAssert(bvSort, "");
302
0
    smtAssert(bvSort->size <= 256, "");
303
0
    return Expression(
304
0
      "bv2int",
305
0
      std::vector<Expression>{std::move(_bv)},
306
0
      SortProvider::intSort(_signed)
307
0
    );
308
0
  }
309
310
  static bool sameSort(std::vector<Expression> const& _args)
311
0
  {
312
0
    if (_args.empty())
313
0
      return true;
314
0
315
0
    auto sort = _args.front().sort;
316
0
    return ranges::all_of(
317
0
      _args,
318
0
      [&](auto const& _expr){ return _expr.sort->kind == sort->kind; }
319
0
    );
320
0
  }
321
322
  static Expression mkAnd(std::vector<Expression> _args)
323
0
  {
324
0
    smtAssert(!_args.empty(), "");
325
0
    smtAssert(sameSort(_args), "");
326
0
327
0
    auto sort = _args.front().sort;
328
0
    if (sort->kind == Kind::BitVector)
329
0
      return Expression("bvand", std::move(_args), sort);
330
0
331
0
    smtAssert(sort->kind == Kind::Bool, "");
332
0
    return Expression("and", std::move(_args), Kind::Bool);
333
0
  }
334
335
  static Expression mkOr(std::vector<Expression> _args)
336
0
  {
337
0
    smtAssert(!_args.empty(), "");
338
0
    smtAssert(sameSort(_args), "");
339
0
340
0
    auto sort = _args.front().sort;
341
0
    if (sort->kind == Kind::BitVector)
342
0
      return Expression("bvor", std::move(_args), sort);
343
0
344
0
    smtAssert(sort->kind == Kind::Bool, "");
345
0
    return Expression("or", std::move(_args), Kind::Bool);
346
0
  }
347
348
  static Expression mkPlus(std::vector<Expression> _args)
349
0
  {
350
0
    smtAssert(!_args.empty(), "");
351
0
    smtAssert(sameSort(_args), "");
352
0
353
0
    auto sort = _args.front().sort;
354
0
    smtAssert(sort->kind == Kind::BitVector || sort->kind == Kind::Int, "");
355
0
    return Expression("+", std::move(_args), sort);
356
0
  }
357
358
  static Expression mkMul(std::vector<Expression> _args)
359
0
  {
360
0
    smtAssert(!_args.empty(), "");
361
0
    smtAssert(sameSort(_args), "");
362
0
363
0
    auto sort = _args.front().sort;
364
0
    smtAssert(sort->kind == Kind::BitVector || sort->kind == Kind::Int, "");
365
0
    return Expression("*", std::move(_args), sort);
366
0
  }
367
368
  friend Expression operator!(Expression _a)
369
0
  {
370
0
    if (_a.sort->kind == Kind::BitVector)
371
0
      return ~_a;
372
0
    return Expression("not", std::move(_a), Kind::Bool);
373
0
  }
374
  friend Expression operator&&(Expression _a, Expression _b)
375
0
  {
376
0
    if (_a.sort->kind == Kind::BitVector)
377
0
    {
378
0
      smtAssert(_b.sort->kind == Kind::BitVector, "");
379
0
      return _a & _b;
380
0
    }
381
0
    return Expression("and", std::move(_a), std::move(_b), Kind::Bool);
382
0
  }
383
  friend Expression operator||(Expression _a, Expression _b)
384
0
  {
385
0
    if (_a.sort->kind == Kind::BitVector)
386
0
    {
387
0
      smtAssert(_b.sort->kind == Kind::BitVector, "");
388
0
      return _a | _b;
389
0
    }
390
0
    return Expression("or", std::move(_a), std::move(_b), Kind::Bool);
391
0
  }
392
  friend Expression operator==(Expression _a, Expression _b)
393
0
  {
394
0
    smtAssert(_a.sort->kind == _b.sort->kind, "Trying to create an 'equal' expression with different sorts");
395
0
    return Expression("=", std::move(_a), std::move(_b), Kind::Bool);
396
0
  }
397
  friend Expression operator!=(Expression _a, Expression _b)
398
0
  {
399
0
    return !(std::move(_a) == std::move(_b));
400
0
  }
401
  friend Expression operator<(Expression _a, Expression _b)
402
0
  {
403
0
    return Expression("<", std::move(_a), std::move(_b), Kind::Bool);
404
0
  }
405
  friend Expression operator<=(Expression _a, Expression _b)
406
0
  {
407
0
    return Expression("<=", std::move(_a), std::move(_b), Kind::Bool);
408
0
  }
409
  friend Expression operator>(Expression _a, Expression _b)
410
0
  {
411
0
    return Expression(">", std::move(_a), std::move(_b), Kind::Bool);
412
0
  }
413
  friend Expression operator>=(Expression _a, Expression _b)
414
0
  {
415
0
    return Expression(">=", std::move(_a), std::move(_b), Kind::Bool);
416
0
  }
417
  friend Expression operator+(Expression _a, Expression _b)
418
0
  {
419
0
    auto intSort = _a.sort;
420
0
    return Expression("+", {std::move(_a), std::move(_b)}, intSort);
421
0
  }
422
  friend Expression operator-(Expression _a, Expression _b)
423
0
  {
424
0
    auto intSort = _a.sort;
425
0
    return Expression("-", {std::move(_a), std::move(_b)}, intSort);
426
0
  }
427
  friend Expression operator*(Expression _a, Expression _b)
428
0
  {
429
0
    auto intSort = _a.sort;
430
0
    return Expression("*", {std::move(_a), std::move(_b)}, intSort);
431
0
  }
432
  friend Expression operator/(Expression _a, Expression _b)
433
0
  {
434
0
    auto intSort = _a.sort;
435
0
    return Expression("div", {std::move(_a), std::move(_b)}, intSort);
436
0
  }
437
  friend Expression operator%(Expression _a, Expression _b)
438
0
  {
439
0
    auto intSort = _a.sort;
440
0
    return Expression("mod", {std::move(_a), std::move(_b)}, intSort);
441
0
  }
442
  friend Expression operator~(Expression _a)
443
0
  {
444
0
    auto bvSort = _a.sort;
445
0
    return Expression("bvnot", {std::move(_a)}, bvSort);
446
0
  }
447
  friend Expression operator&(Expression _a, Expression _b)
448
0
  {
449
0
    auto bvSort = _a.sort;
450
0
    return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort);
451
0
  }
452
  friend Expression operator|(Expression _a, Expression _b)
453
0
  {
454
0
    auto bvSort = _a.sort;
455
0
    return Expression("bvor", {std::move(_a), std::move(_b)}, bvSort);
456
0
  }
457
  friend Expression operator^(Expression _a, Expression _b)
458
0
  {
459
0
    auto bvSort = _a.sort;
460
0
    return Expression("bvxor", {std::move(_a), std::move(_b)}, bvSort);
461
0
  }
462
  friend Expression operator<<(Expression _a, Expression _b)
463
0
  {
464
0
    auto bvSort = _a.sort;
465
0
    return Expression("bvshl", {std::move(_a), std::move(_b)}, bvSort);
466
0
  }
467
  friend Expression operator>>(Expression _a, Expression _b)
468
0
  {
469
0
    auto bvSort = _a.sort;
470
0
    return Expression("bvlshr", {std::move(_a), std::move(_b)}, bvSort);
471
0
  }
472
  static Expression ashr(Expression _a, Expression _b)
473
0
  {
474
0
    auto bvSort = _a.sort;
475
0
    return Expression("bvashr", {std::move(_a), std::move(_b)}, bvSort);
476
0
  }
477
  Expression operator()(std::vector<Expression> _arguments) const
478
0
  {
479
0
    smtAssert(
480
0
      sort->kind == Kind::Function,
481
0
      "Attempted function application to non-function."
482
0
    );
483
0
    auto fSort = dynamic_cast<FunctionSort const*>(sort.get());
484
0
    smtAssert(fSort, "");
485
0
    return Expression(name, std::move(_arguments), fSort->codomain);
486
0
  }
487
488
  std::string name;
489
  std::vector<Expression> arguments;
490
  SortPointer sort;
491
492
private:
493
  /// Manual constructors, should only be used by SolverInterface and this class itself.
494
  Expression(std::string _name, std::vector<Expression> _arguments, Kind _kind):
495
0
    Expression(std::move(_name), std::move(_arguments), std::make_shared<Sort>(_kind)) {}
496
497
  explicit Expression(std::string _name, Kind _kind):
498
0
    Expression(std::move(_name), std::vector<Expression>{}, _kind) {}
499
  Expression(std::string _name, Expression _arg, Kind _kind):
500
0
    Expression(std::move(_name), std::vector<Expression>{std::move(_arg)}, _kind) {}
501
  Expression(std::string _name, Expression _arg1, Expression _arg2, Kind _kind):
502
0
    Expression(std::move(_name), std::vector<Expression>{std::move(_arg1), std::move(_arg2)}, _kind) {}
503
};
504
505
DEV_SIMPLE_EXCEPTION(SolverError);
506
507
class SolverInterface
508
{
509
public:
510
0
  SolverInterface(std::optional<unsigned> _queryTimeout = {}): m_queryTimeout(_queryTimeout) {}
511
512
0
  virtual ~SolverInterface() = default;
513
  virtual void reset() = 0;
514
515
  virtual void push() = 0;
516
  virtual void pop() = 0;
517
518
  virtual void declareVariable(std::string const& _name, SortPointer const& _sort) = 0;
519
  Expression newVariable(std::string _name, SortPointer const& _sort)
520
0
  {
521
    // Subclasses should do something here
522
0
    smtAssert(_sort, "");
523
0
    declareVariable(_name, _sort);
524
0
    return Expression(std::move(_name), {}, _sort);
525
0
  }
526
527
  virtual void addAssertion(Expression const& _expr) = 0;
528
529
  /// Checks for satisfiability, evaluates the expressions if a model
530
  /// is available. Throws SMTSolverError on error.
531
  virtual std::pair<CheckResult, std::vector<std::string>>
532
  check(std::vector<Expression> const& _expressionsToEvaluate) = 0;
533
534
  /// @returns a list of queries that the system was not able to respond to.
535
0
  virtual std::vector<std::string> unhandledQueries() { return {}; }
536
537
  /// @returns how many SMT solvers this interface has.
538
0
  virtual size_t solvers() { return 1; }
539
540
protected:
541
  std::optional<unsigned> m_queryTimeout;
542
};
543
544
}