Coverage Report

Created: 2026-10-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/formal/ArraySlicePredicate.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/ArraySlicePredicate.h>
20
21
#include <libsolidity/formal/SymbolicVariables.h>
22
23
#include <liblangutil/Exceptions.h>
24
25
using namespace solidity;
26
using namespace solidity::smtutil;
27
using namespace solidity::frontend;
28
using namespace solidity::frontend::smt;
29
30
std::map<std::string, ArraySlicePredicate::SliceData> ArraySlicePredicate::m_slicePredicates;
31
32
std::pair<bool, ArraySlicePredicate::SliceData const&> ArraySlicePredicate::create(SortPointer _sort, EncodingContext& _context)
33
801
{
34
801
  solAssert(_sort->kind == Kind::Tuple, "");
35
801
  auto tupleSort = std::dynamic_pointer_cast<TupleSort>(_sort);
36
801
  solAssert(tupleSort, "");
37
38
801
  auto tupleName = tupleSort->name;
39
801
  if (m_slicePredicates.count(tupleName))
40
675
    return {true, m_slicePredicates.at(tupleName)};
41
42
126
  auto sort = tupleSort->components.at(0);
43
126
  solAssert(sort->kind == Kind::Array, "");
44
45
126
  smt::SymbolicArrayVariable aVar{sort, "a_" + tupleName, _context };
46
126
  smt::SymbolicArrayVariable bVar{sort, "b_" + tupleName, _context};
47
126
  smt::SymbolicIntVariable startVar{TypeProvider::uint256(), TypeProvider::uint256(), "start_" + tupleName, _context};
48
126
  smt::SymbolicIntVariable endVar{TypeProvider::uint256(), TypeProvider::uint256(), "end_" + tupleName, _context };
49
126
  smt::SymbolicIntVariable iVar{TypeProvider::uint256(), TypeProvider::uint256(), "i_" + tupleName, _context};
50
51
126
  std::vector<SortPointer> domain{sort, sort, startVar.sort(), endVar.sort()};
52
126
  auto sliceSort = std::make_shared<FunctionSort>(domain, SortProvider::boolSort);
53
126
  Predicate const& slice = *Predicate::create(sliceSort, "array_slice_" + tupleName, PredicateType::Custom, _context);
54
55
126
  domain.emplace_back(iVar.sort());
56
126
  auto predSort = std::make_shared<FunctionSort>(domain, SortProvider::boolSort);
57
126
  Predicate const& header = *Predicate::create(predSort, "array_slice_header_" + tupleName, PredicateType::Custom, _context);
58
126
  Predicate const& loop = *Predicate::create(predSort, "array_slice_loop_" + tupleName, PredicateType::Custom, _context);
59
60
126
  auto a = aVar.elements();
61
126
  auto b = bVar.elements();
62
126
  auto start = startVar.currentValue();
63
126
  auto end = endVar.currentValue();
64
126
  auto i = iVar.currentValue();
65
66
126
  auto rule1 = smtutil::Expression::implies(
67
126
    end > start,
68
126
    header({a, b, start, end, 0})
69
126
  );
70
71
126
  auto rule2 = smtutil::Expression::implies(
72
126
    header({a, b, start, end, i}) && i >= (end - start),
73
126
    slice({a, b, start, end})
74
126
  );
75
76
126
  auto rule3 = smtutil::Expression::implies(
77
126
    header({a, b, start, end, i}) && i >= 0 && i < (end - start),
78
126
    loop({a, b, start, end, i})
79
126
  );
80
81
126
  auto b_i = smtutil::Expression::select(b, i);
82
126
  auto a_start_i = smtutil::Expression::select(a, start + i);
83
126
  auto rule4 = smtutil::Expression::implies(
84
126
    loop({a, b, start, end, i}) && b_i == a_start_i,
85
126
    header({a, b, start, end, i + 1})
86
126
  );
87
88
126
  return {false, m_slicePredicates[tupleName] = {
89
126
    {&slice, &header, &loop},
90
126
    {std::move(rule1), std::move(rule2), std::move(rule3), std::move(rule4)}
91
126
  }};
92
801
}