/src/solidity/test/tools/yulInterpreter/EVMInstructionInterpreter.h
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 | | * Yul interpreter module that evaluates EVM instructions. |
20 | | */ |
21 | | |
22 | | #pragma once |
23 | | |
24 | | #include <libyul/ASTForward.h> |
25 | | |
26 | | #include <libsolutil/CommonData.h> |
27 | | #include <libsolutil/FixedHash.h> |
28 | | #include <libsolutil/Numeric.h> |
29 | | |
30 | | #include <liblangutil/EVMVersion.h> |
31 | | |
32 | | #include <vector> |
33 | | |
34 | | namespace solidity::evmasm |
35 | | { |
36 | | enum class Instruction: uint8_t; |
37 | | } |
38 | | |
39 | | namespace solidity::yul |
40 | | { |
41 | | class YulString; |
42 | | struct BuiltinFunctionForEVM; |
43 | | } |
44 | | |
45 | | namespace solidity::yul::test |
46 | | { |
47 | | |
48 | | /// Copy @a _size bytes of @a _source at offset @a _sourceOffset to |
49 | | /// @a _target at offset @a _targetOffset. Behaves as if @a _source would |
50 | | /// continue with an infinite sequence of zero bytes beyond its end. |
51 | | void copyZeroExtended( |
52 | | std::map<u256, uint8_t>& _target, |
53 | | bytes const& _source, |
54 | | size_t _targetOffset, |
55 | | size_t _sourceOffset, |
56 | | size_t _size |
57 | | ); |
58 | | |
59 | | /// Copy @a _size bytes of @a _source at offset @a _sourceOffset to |
60 | | /// @a _target at offset @a _targetOffset. Behaves as if @a _source would |
61 | | /// continue with an infinite sequence of zero bytes beyond its end. |
62 | | /// When target and source areas overlap, behaves as if the data was copied |
63 | | /// using an intermediate buffer. |
64 | | void copyZeroExtendedWithOverlap( |
65 | | std::map<u256, uint8_t>& _target, |
66 | | std::map<u256, uint8_t> const& _source, |
67 | | size_t _targetOffset, |
68 | | size_t _sourceOffset, |
69 | | size_t _size |
70 | | ); |
71 | | |
72 | | struct InterpreterState; |
73 | | |
74 | | /** |
75 | | * Interprets EVM instructions based on the current state and logs instructions with |
76 | | * side-effects. |
77 | | * |
78 | | * Since this is mainly meant to be used for differential fuzz testing, it is focused |
79 | | * on a single contract only, does not do any gas counting and differs from the correct |
80 | | * implementation in many ways: |
81 | | * |
82 | | * - If memory access to a "large" memory position is performed, a deterministic |
83 | | * value is returned. Data that is stored in a "large" memory position is not |
84 | | * retained. |
85 | | * - The blockhash instruction returns a fixed value if the argument is in range. |
86 | | * - Extcodesize returns a deterministic value depending on the address. |
87 | | * - Extcodecopy copies a deterministic value depending on the address. |
88 | | * - And many other things |
89 | | * |
90 | | * The main focus is that the generated execution trace is the same for equivalent executions |
91 | | * and likely to be different for non-equivalent executions. |
92 | | */ |
93 | | class EVMInstructionInterpreter |
94 | | { |
95 | | public: |
96 | | explicit EVMInstructionInterpreter(langutil::EVMVersion _evmVersion, InterpreterState& _state, bool _disableMemWriteTrace): |
97 | 3.60M | m_evmVersion(_evmVersion), |
98 | 3.60M | m_state(_state), |
99 | 3.60M | m_disableMemoryWriteInstructions(_disableMemWriteTrace) |
100 | 3.60M | {} |
101 | | /// Evaluate instruction |
102 | | u256 eval(evmasm::Instruction _instruction, std::vector<u256> const& _arguments); |
103 | | /// Evaluate builtin function |
104 | | u256 evalBuiltin( |
105 | | BuiltinFunctionForEVM const& _fun, |
106 | | std::vector<Expression> const& _arguments, |
107 | | std::vector<u256> const& _evaluatedArguments |
108 | | ); |
109 | | |
110 | | /// @returns the blob versioned hash |
111 | | util::h256 blobHash(u256 const& _index); |
112 | | |
113 | | private: |
114 | | /// Checks if the memory access is valid and adjusts msize accordingly. |
115 | | /// @returns true if memory access is valid, false otherwise |
116 | | /// A valid memory access must satisfy all of the following pre-requisites: |
117 | | /// - Sum of @param _offset and @param _size do not overflow modulo u256 |
118 | | /// - Sum of @param _offset, @param _size, and 31 do not overflow modulo u256 (see note below) |
119 | | /// - @param _size is lesser than or equal to @a s_maxRangeSize |
120 | | /// - @param _offset is lesser than or equal to the difference of numeric_limits<size_t>::max() |
121 | | /// and @a s_maxRangeSize |
122 | | /// Note: Memory expansion is carried out in multiples of 32 bytes. |
123 | | bool accessMemory(u256 const& _offset, u256 const& _size = 32); |
124 | | /// @returns the memory contents at the provided address. |
125 | | /// Does not adjust msize, use @a accessMemory for that |
126 | | bytes readMemory(u256 const& _offset, u256 const& _size = 32); |
127 | | /// @returns the memory contents at the provided address. |
128 | | /// Does not adjust msize, use @a accessMemory for that |
129 | | u256 readMemoryWord(u256 const& _offset); |
130 | | /// @returns writes a word to memory |
131 | | /// Does not adjust msize, use @a accessMemory for that |
132 | | void writeMemoryWord(u256 const& _offset, u256 const& _value); |
133 | | |
134 | | void logTrace( |
135 | | evmasm::Instruction _instruction, |
136 | | std::vector<u256> const& _arguments = {}, |
137 | | bytes const& _data = {} |
138 | | ); |
139 | | /// Appends a log to the trace representing an instruction or similar operation by string, |
140 | | /// with arguments and auxiliary data (if nonempty). Flag @param _writesToMemory indicates |
141 | | /// whether the instruction writes to (true) or does not write to (false) memory. |
142 | | void logTrace( |
143 | | std::string const& _pseudoInstruction, |
144 | | bool _writesToMemory, |
145 | | std::vector<u256> const& _arguments = {}, |
146 | | bytes const& _data = {} |
147 | | ); |
148 | | |
149 | | /// @returns a pair of boolean and size_t whose first value is true if @param _pseudoInstruction |
150 | | /// is a Yul instruction that the Yul optimizer's loadResolver step rewrites the input |
151 | | /// memory pointer value to zero if that instruction's read length (contained within @param |
152 | | // _arguments) is zero, and whose second value is the positional index of the input memory |
153 | | // pointer argument. |
154 | | /// If the Yul instruction is unaffected or affected but read length is non-zero, the first |
155 | | /// value is false. |
156 | | std::pair<bool, size_t> isInputMemoryPtrModified( |
157 | | std::string const& _pseudoInstruction, |
158 | | std::vector<u256> const& _arguments |
159 | | ); |
160 | | |
161 | | /// @returns disable trace flag. |
162 | | bool memWriteTracingDisabled() |
163 | 144k | { |
164 | 144k | return m_disableMemoryWriteInstructions; |
165 | 144k | } |
166 | | |
167 | | langutil::EVMVersion m_evmVersion; |
168 | | InterpreterState& m_state; |
169 | | /// Flag to disable trace of instructions that write to memory. |
170 | | bool m_disableMemoryWriteInstructions; |
171 | | /// mapping from linker identifier (hash of literal) to original string representation, populated by linkersymbol |
172 | | /// calls |
173 | | std::map<util::h256, std::string> m_linkerSymbols; |
174 | | |
175 | | public: |
176 | | /// Maximum length for range-based memory access operations. |
177 | | static constexpr unsigned s_maxRangeSize = 0xffff; |
178 | | }; |
179 | | |
180 | | } // solidity::yul::test |