/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 | } |