/src/solidity/test/tools/yulInterpreter/EVMInstructionInterpreter.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 | | * Yul interpreter module that evaluates EVM instructions. |
20 | | */ |
21 | | |
22 | | #include <test/tools/yulInterpreter/EVMInstructionInterpreter.h> |
23 | | |
24 | | #include <test/tools/yulInterpreter/Interpreter.h> |
25 | | |
26 | | #include <libyul/backends/evm/EVMDialect.h> |
27 | | #include <libyul/AST.h> |
28 | | |
29 | | #include <libevmasm/Instruction.h> |
30 | | #include <libevmasm/SemanticInformation.h> |
31 | | |
32 | | #include <libsolutil/Keccak256.h> |
33 | | #include <libsolutil/Numeric.h> |
34 | | |
35 | | #include <limits> |
36 | | |
37 | | using namespace std; |
38 | | using namespace solidity; |
39 | | using namespace solidity::evmasm; |
40 | | using namespace solidity::yul; |
41 | | using namespace solidity::yul::test; |
42 | | |
43 | | using solidity::util::h160; |
44 | | using solidity::util::h256; |
45 | | using solidity::util::keccak256; |
46 | | |
47 | | namespace |
48 | | { |
49 | | |
50 | | /// Reads 32 bytes from @a _data at position @a _offset bytes while |
51 | | /// interpreting @a _data to be padded with an infinite number of zero |
52 | | /// bytes beyond its end. |
53 | | u256 readZeroExtended(bytes const& _data, u256 const& _offset) |
54 | 26.2k | { |
55 | 26.2k | if (_offset >= _data.size()) |
56 | 17.7k | return 0; |
57 | 8.45k | else if (_offset + 32 <= _data.size()) |
58 | 7.99k | return *reinterpret_cast<h256 const*>(_data.data() + static_cast<size_t>(_offset)); |
59 | 458 | else |
60 | 458 | { |
61 | 458 | size_t off = static_cast<size_t>(_offset); |
62 | 458 | u256 val; |
63 | 15.1k | for (size_t i = 0; i < 32; ++i) |
64 | 14.6k | { |
65 | 14.6k | val <<= 8; |
66 | 14.6k | if (off + i < _data.size()) |
67 | 2.69k | val += _data[off + i]; |
68 | 14.6k | } |
69 | 458 | return val; |
70 | 458 | } |
71 | 26.2k | } |
72 | | |
73 | | /// Copy @a _size bytes of @a _source at offset @a _sourceOffset to |
74 | | /// @a _target at offset @a _targetOffset. Behaves as if @a _source would |
75 | | /// continue with an infinite sequence of zero bytes beyond its end. |
76 | | void copyZeroExtended( |
77 | | map<u256, uint8_t>& _target, bytes const& _source, |
78 | | size_t _targetOffset, size_t _sourceOffset, size_t _size |
79 | | ) |
80 | 7.85k | { |
81 | 24.6M | for (size_t i = 0; i < _size; ++i) |
82 | 24.6M | _target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0; |
83 | 7.85k | } |
84 | | |
85 | | } |
86 | | |
87 | | using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; |
88 | | |
89 | | u256 EVMInstructionInterpreter::eval( |
90 | | evmasm::Instruction _instruction, |
91 | | vector<u256> const& _arguments |
92 | | ) |
93 | 1.69M | { |
94 | 1.69M | using namespace solidity::evmasm; |
95 | 1.69M | using evmasm::Instruction; |
96 | | |
97 | 1.69M | auto info = instructionInfo(_instruction); |
98 | 1.69M | yulAssert(static_cast<size_t>(info.args) == _arguments.size(), ""); |
99 | | |
100 | 1.69M | auto const& arg = _arguments; |
101 | 1.69M | switch (_instruction) |
102 | 1.69M | { |
103 | 642 | case Instruction::STOP: |
104 | 642 | logTrace(_instruction); |
105 | 642 | BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); |
106 | | // --------------- arithmetic --------------- |
107 | 100k | case Instruction::ADD: |
108 | 100k | return arg[0] + arg[1]; |
109 | 43.5k | case Instruction::MUL: |
110 | 43.5k | return arg[0] * arg[1]; |
111 | 54.4k | case Instruction::SUB: |
112 | 54.4k | return arg[0] - arg[1]; |
113 | 87.8k | case Instruction::DIV: |
114 | 87.8k | return arg[1] == 0 ? 0 : arg[0] / arg[1]; |
115 | 55.1k | case Instruction::SDIV: |
116 | 55.1k | return arg[1] == 0 ? 0 : s2u(u2s(arg[0]) / u2s(arg[1])); |
117 | 25.3k | case Instruction::MOD: |
118 | 25.3k | return arg[1] == 0 ? 0 : arg[0] % arg[1]; |
119 | 23.1k | case Instruction::SMOD: |
120 | 23.1k | return arg[1] == 0 ? 0 : s2u(u2s(arg[0]) % u2s(arg[1])); |
121 | 29.8k | case Instruction::EXP: |
122 | 29.8k | return exp256(arg[0], arg[1]); |
123 | 139k | case Instruction::NOT: |
124 | 139k | return ~arg[0]; |
125 | 88.0k | case Instruction::LT: |
126 | 88.0k | return arg[0] < arg[1] ? 1 : 0; |
127 | 6.59k | case Instruction::GT: |
128 | 6.59k | return arg[0] > arg[1] ? 1 : 0; |
129 | 2.39k | case Instruction::SLT: |
130 | 2.39k | return u2s(arg[0]) < u2s(arg[1]) ? 1 : 0; |
131 | 6.09k | case Instruction::SGT: |
132 | 6.09k | return u2s(arg[0]) > u2s(arg[1]) ? 1 : 0; |
133 | 5.85k | case Instruction::EQ: |
134 | 5.85k | return arg[0] == arg[1] ? 1 : 0; |
135 | 10.6k | case Instruction::ISZERO: |
136 | 10.6k | return arg[0] == 0 ? 1 : 0; |
137 | 7.71k | case Instruction::AND: |
138 | 7.71k | return arg[0] & arg[1]; |
139 | 64.6k | case Instruction::OR: |
140 | 64.6k | return arg[0] | arg[1]; |
141 | 16.1k | case Instruction::XOR: |
142 | 16.1k | return arg[0] ^ arg[1]; |
143 | 6.98k | case Instruction::BYTE: |
144 | 6.98k | return arg[0] >= 32 ? 0 : (arg[1] >> unsigned(8 * (31 - arg[0]))) & 0xff; |
145 | 72.9k | case Instruction::SHL: |
146 | 72.9k | return arg[0] > 255 ? 0 : (arg[1] << unsigned(arg[0])); |
147 | 21.5k | case Instruction::SHR: |
148 | 21.5k | return arg[0] > 255 ? 0 : (arg[1] >> unsigned(arg[0])); |
149 | 31.4k | case Instruction::SAR: |
150 | 31.4k | { |
151 | 31.4k | static u256 const hibit = u256(1) << 255; |
152 | 31.4k | if (arg[0] >= 256) |
153 | 6.84k | return arg[1] & hibit ? u256(-1) : 0; |
154 | 24.6k | else |
155 | 24.6k | { |
156 | 24.6k | unsigned amount = unsigned(arg[0]); |
157 | 24.6k | u256 v = arg[1] >> amount; |
158 | 24.6k | if (arg[1] & hibit) |
159 | 2.73k | v |= u256(-1) << (256 - amount); |
160 | 24.6k | return v; |
161 | 24.6k | } |
162 | 31.4k | } |
163 | 53.1k | case Instruction::ADDMOD: |
164 | 53.1k | return arg[2] == 0 ? 0 : u256((u512(arg[0]) + u512(arg[1])) % arg[2]); |
165 | 43.6k | case Instruction::MULMOD: |
166 | 43.6k | return arg[2] == 0 ? 0 : u256((u512(arg[0]) * u512(arg[1])) % arg[2]); |
167 | 13.8k | case Instruction::SIGNEXTEND: |
168 | 13.8k | if (arg[0] >= 31) |
169 | 4.98k | return arg[1]; |
170 | 8.90k | else |
171 | 8.90k | { |
172 | 8.90k | unsigned testBit = unsigned(arg[0]) * 8 + 7; |
173 | 8.90k | u256 ret = arg[1]; |
174 | 8.90k | u256 mask = ((u256(1) << testBit) - 1); |
175 | 8.90k | if (boost::multiprecision::bit_test(ret, testBit)) |
176 | 2.94k | ret |= ~mask; |
177 | 5.96k | else |
178 | 5.96k | ret &= mask; |
179 | 8.90k | return ret; |
180 | 8.90k | } |
181 | | // --------------- blockchain stuff --------------- |
182 | 27.4k | case Instruction::KECCAK256: |
183 | 27.4k | { |
184 | 27.4k | if (!accessMemory(arg[0], arg[1])) |
185 | 18.7k | return u256("0x1234cafe1234cafe1234cafe") + arg[0]; |
186 | 8.66k | uint64_t offset = uint64_t(arg[0] & uint64_t(-1)); |
187 | 8.66k | uint64_t size = uint64_t(arg[1] & uint64_t(-1)); |
188 | 8.66k | return u256(keccak256(readMemory(offset, size))); |
189 | 27.4k | } |
190 | 5.75k | case Instruction::ADDRESS: |
191 | 5.75k | return h256(m_state.address, h256::AlignRight); |
192 | 3.92k | case Instruction::BALANCE: |
193 | 3.92k | if (arg[0] == h256(m_state.address, h256::AlignRight)) |
194 | 68 | return m_state.selfbalance; |
195 | 3.85k | else |
196 | 3.85k | return m_state.balance; |
197 | 2.02k | case Instruction::SELFBALANCE: |
198 | 2.02k | return m_state.selfbalance; |
199 | 10.7k | case Instruction::ORIGIN: |
200 | 10.7k | return h256(m_state.origin, h256::AlignRight); |
201 | 3.98k | case Instruction::CALLER: |
202 | 3.98k | return h256(m_state.caller, h256::AlignRight); |
203 | 2.04k | case Instruction::CALLVALUE: |
204 | 2.04k | return m_state.callvalue; |
205 | 26.2k | case Instruction::CALLDATALOAD: |
206 | 26.2k | return readZeroExtended(m_state.calldata, arg[0]); |
207 | 3.81k | case Instruction::CALLDATASIZE: |
208 | 3.81k | return m_state.calldata.size(); |
209 | 5.74k | case Instruction::CALLDATACOPY: |
210 | 5.74k | logTrace(_instruction, arg); |
211 | 5.74k | if (accessMemory(arg[0], arg[2])) |
212 | 1.09k | copyZeroExtended( |
213 | 1.09k | m_state.memory, m_state.calldata, |
214 | 1.09k | size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) |
215 | 1.09k | ); |
216 | 5.74k | return 0; |
217 | 5.98k | case Instruction::CODESIZE: |
218 | 5.98k | return m_state.code.size(); |
219 | 7.11k | case Instruction::CODECOPY: |
220 | 7.11k | logTrace(_instruction, arg); |
221 | 7.11k | if (accessMemory(arg[0], arg[2])) |
222 | 1.86k | copyZeroExtended( |
223 | 1.86k | m_state.memory, m_state.code, |
224 | 1.86k | size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) |
225 | 1.86k | ); |
226 | 7.11k | return 0; |
227 | 3.14k | case Instruction::GASPRICE: |
228 | 3.14k | return m_state.gasprice; |
229 | 4.74k | case Instruction::CHAINID: |
230 | 4.74k | return m_state.chainid; |
231 | 0 | case Instruction::BASEFEE: |
232 | 0 | return m_state.basefee; |
233 | 4.12k | case Instruction::EXTCODESIZE: |
234 | 4.12k | return u256(keccak256(h256(arg[0]))) & 0xffffff; |
235 | 5.58k | case Instruction::EXTCODEHASH: |
236 | 5.58k | return u256(keccak256(h256(arg[0] + 1))); |
237 | 14.8k | case Instruction::EXTCODECOPY: |
238 | 14.8k | logTrace(_instruction, arg); |
239 | 14.8k | if (accessMemory(arg[1], arg[3])) |
240 | | // TODO this way extcodecopy and codecopy do the same thing. |
241 | 3.16k | copyZeroExtended( |
242 | 3.16k | m_state.memory, m_state.code, |
243 | 3.16k | size_t(arg[1]), size_t(arg[2]), size_t(arg[3]) |
244 | 3.16k | ); |
245 | 14.8k | return 0; |
246 | 1.92k | case Instruction::RETURNDATASIZE: |
247 | 1.92k | return m_state.returndata.size(); |
248 | 2.06k | case Instruction::RETURNDATACOPY: |
249 | 2.06k | logTrace(_instruction, arg); |
250 | 2.06k | if (accessMemory(arg[0], arg[2])) |
251 | 619 | copyZeroExtended( |
252 | 619 | m_state.memory, m_state.returndata, |
253 | 619 | size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) |
254 | 619 | ); |
255 | 2.06k | return 0; |
256 | 6.25k | case Instruction::BLOCKHASH: |
257 | 6.25k | if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber) |
258 | 5.72k | return 0; |
259 | 530 | else |
260 | 530 | return 0xaaaaaaaa + (arg[0] - m_state.blockNumber - 256); |
261 | 5.62k | case Instruction::COINBASE: |
262 | 5.62k | return h256(m_state.coinbase, h256::AlignRight); |
263 | 2.39k | case Instruction::TIMESTAMP: |
264 | 2.39k | return m_state.timestamp; |
265 | 3.14k | case Instruction::NUMBER: |
266 | 3.14k | return m_state.blockNumber; |
267 | 3.62k | case Instruction::DIFFICULTY: |
268 | 3.62k | return m_state.difficulty; |
269 | 1.93k | case Instruction::GASLIMIT: |
270 | 1.93k | return m_state.gaslimit; |
271 | | // --------------- memory / storage / logs --------------- |
272 | 78.6k | case Instruction::MLOAD: |
273 | 78.6k | accessMemory(arg[0], 0x20); |
274 | 78.6k | return readMemoryWord(arg[0]); |
275 | 84.4k | case Instruction::MSTORE: |
276 | 84.4k | accessMemory(arg[0], 0x20); |
277 | 84.4k | writeMemoryWord(arg[0], arg[1]); |
278 | 84.4k | return 0; |
279 | 10.8k | case Instruction::MSTORE8: |
280 | 10.8k | accessMemory(arg[0], 1); |
281 | 10.8k | m_state.memory[arg[0]] = uint8_t(arg[1] & 0xff); |
282 | 10.8k | return 0; |
283 | 58.3k | case Instruction::SLOAD: |
284 | 58.3k | return m_state.storage[h256(arg[0])]; |
285 | 107k | case Instruction::SSTORE: |
286 | 107k | m_state.storage[h256(arg[0])] = h256(arg[1]); |
287 | 107k | return 0; |
288 | 0 | case Instruction::PC: |
289 | 0 | return 0x77; |
290 | 39.7k | case Instruction::MSIZE: |
291 | 39.7k | return m_state.msize; |
292 | 19.3k | case Instruction::GAS: |
293 | 19.3k | return 0x99; |
294 | 4.47k | case Instruction::LOG0: |
295 | 4.47k | accessMemory(arg[0], arg[1]); |
296 | 4.47k | logTrace(_instruction, arg); |
297 | 4.47k | return 0; |
298 | 5.68k | case Instruction::LOG1: |
299 | 5.68k | accessMemory(arg[0], arg[1]); |
300 | 5.68k | logTrace(_instruction, arg); |
301 | 5.68k | return 0; |
302 | 1.70k | case Instruction::LOG2: |
303 | 1.70k | accessMemory(arg[0], arg[1]); |
304 | 1.70k | logTrace(_instruction, arg); |
305 | 1.70k | return 0; |
306 | 855 | case Instruction::LOG3: |
307 | 855 | accessMemory(arg[0], arg[1]); |
308 | 855 | logTrace(_instruction, arg); |
309 | 855 | return 0; |
310 | 1.19k | case Instruction::LOG4: |
311 | 1.19k | accessMemory(arg[0], arg[1]); |
312 | 1.19k | logTrace(_instruction, arg); |
313 | 1.19k | return 0; |
314 | | // --------------- calls --------------- |
315 | 27.7k | case Instruction::CREATE: |
316 | 27.7k | accessMemory(arg[1], arg[2]); |
317 | 27.7k | logTrace(_instruction, arg); |
318 | 27.7k | return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); |
319 | 5.01k | case Instruction::CREATE2: |
320 | 5.01k | accessMemory(arg[2], arg[3]); |
321 | 5.01k | logTrace(_instruction, arg); |
322 | 5.01k | return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); |
323 | 47.7k | case Instruction::CALL: |
324 | 51.0k | case Instruction::CALLCODE: |
325 | | // TODO assign returndata |
326 | 51.0k | accessMemory(arg[3], arg[4]); |
327 | 51.0k | accessMemory(arg[5], arg[6]); |
328 | 51.0k | logTrace(_instruction, arg); |
329 | 51.0k | return arg[0] & 1; |
330 | 2.08k | case Instruction::DELEGATECALL: |
331 | 4.05k | case Instruction::STATICCALL: |
332 | 4.05k | accessMemory(arg[2], arg[3]); |
333 | 4.05k | accessMemory(arg[4], arg[5]); |
334 | 4.05k | logTrace(_instruction, arg); |
335 | 4.05k | return 0; |
336 | 624 | case Instruction::RETURN: |
337 | 624 | { |
338 | 624 | bytes data; |
339 | 624 | if (accessMemory(arg[0], arg[1])) |
340 | 181 | data = readMemory(arg[0], arg[1]); |
341 | 624 | logTrace(_instruction, arg, data); |
342 | 624 | BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); |
343 | 2.08k | } |
344 | 257 | case Instruction::REVERT: |
345 | 257 | accessMemory(arg[0], arg[1]); |
346 | 257 | logTrace(_instruction, arg); |
347 | 257 | m_state.storage.clear(); |
348 | 257 | m_state.trace.clear(); |
349 | 257 | BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); |
350 | 446 | case Instruction::INVALID: |
351 | 446 | logTrace(_instruction); |
352 | 446 | m_state.storage.clear(); |
353 | 446 | m_state.trace.clear(); |
354 | 446 | BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); |
355 | 834 | case Instruction::SELFDESTRUCT: |
356 | 834 | logTrace(_instruction, arg); |
357 | 834 | m_state.storage.clear(); |
358 | 834 | m_state.trace.clear(); |
359 | 834 | BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); |
360 | 14.0k | case Instruction::POP: |
361 | 14.0k | break; |
362 | | // --------------- invalid in strict assembly --------------- |
363 | 0 | case Instruction::JUMP: |
364 | 0 | case Instruction::JUMPI: |
365 | 0 | case Instruction::JUMPDEST: |
366 | 0 | case Instruction::PUSH1: |
367 | 0 | case Instruction::PUSH2: |
368 | 0 | case Instruction::PUSH3: |
369 | 0 | case Instruction::PUSH4: |
370 | 0 | case Instruction::PUSH5: |
371 | 0 | case Instruction::PUSH6: |
372 | 0 | case Instruction::PUSH7: |
373 | 0 | case Instruction::PUSH8: |
374 | 0 | case Instruction::PUSH9: |
375 | 0 | case Instruction::PUSH10: |
376 | 0 | case Instruction::PUSH11: |
377 | 0 | case Instruction::PUSH12: |
378 | 0 | case Instruction::PUSH13: |
379 | 0 | case Instruction::PUSH14: |
380 | 0 | case Instruction::PUSH15: |
381 | 0 | case Instruction::PUSH16: |
382 | 0 | case Instruction::PUSH17: |
383 | 0 | case Instruction::PUSH18: |
384 | 0 | case Instruction::PUSH19: |
385 | 0 | case Instruction::PUSH20: |
386 | 0 | case Instruction::PUSH21: |
387 | 0 | case Instruction::PUSH22: |
388 | 0 | case Instruction::PUSH23: |
389 | 0 | case Instruction::PUSH24: |
390 | 0 | case Instruction::PUSH25: |
391 | 0 | case Instruction::PUSH26: |
392 | 0 | case Instruction::PUSH27: |
393 | 0 | case Instruction::PUSH28: |
394 | 0 | case Instruction::PUSH29: |
395 | 0 | case Instruction::PUSH30: |
396 | 0 | case Instruction::PUSH31: |
397 | 0 | case Instruction::PUSH32: |
398 | 0 | case Instruction::DUP1: |
399 | 0 | case Instruction::DUP2: |
400 | 0 | case Instruction::DUP3: |
401 | 0 | case Instruction::DUP4: |
402 | 0 | case Instruction::DUP5: |
403 | 0 | case Instruction::DUP6: |
404 | 0 | case Instruction::DUP7: |
405 | 0 | case Instruction::DUP8: |
406 | 0 | case Instruction::DUP9: |
407 | 0 | case Instruction::DUP10: |
408 | 0 | case Instruction::DUP11: |
409 | 0 | case Instruction::DUP12: |
410 | 0 | case Instruction::DUP13: |
411 | 0 | case Instruction::DUP14: |
412 | 0 | case Instruction::DUP15: |
413 | 0 | case Instruction::DUP16: |
414 | 0 | case Instruction::SWAP1: |
415 | 0 | case Instruction::SWAP2: |
416 | 0 | case Instruction::SWAP3: |
417 | 0 | case Instruction::SWAP4: |
418 | 0 | case Instruction::SWAP5: |
419 | 0 | case Instruction::SWAP6: |
420 | 0 | case Instruction::SWAP7: |
421 | 0 | case Instruction::SWAP8: |
422 | 0 | case Instruction::SWAP9: |
423 | 0 | case Instruction::SWAP10: |
424 | 0 | case Instruction::SWAP11: |
425 | 0 | case Instruction::SWAP12: |
426 | 0 | case Instruction::SWAP13: |
427 | 0 | case Instruction::SWAP14: |
428 | 0 | case Instruction::SWAP15: |
429 | 0 | case Instruction::SWAP16: |
430 | 0 | { |
431 | 0 | yulAssert(false, ""); |
432 | 0 | return 0; |
433 | 0 | } |
434 | 1.69M | } |
435 | | |
436 | 14.0k | return 0; |
437 | 1.69M | } |
438 | | |
439 | | u256 EVMInstructionInterpreter::evalBuiltin( |
440 | | BuiltinFunctionForEVM const& _fun, |
441 | | vector<Expression> const& _arguments, |
442 | | vector<u256> const& _evaluatedArguments |
443 | | ) |
444 | 1.70M | { |
445 | 1.70M | if (_fun.instruction) |
446 | 1.69M | return eval(*_fun.instruction, _evaluatedArguments); |
447 | | |
448 | 15.0k | string fun = _fun.name.str(); |
449 | | // Evaluate datasize/offset/copy instructions |
450 | 15.0k | if (fun == "datasize" || fun == "dataoffset") |
451 | 12.7k | { |
452 | 12.7k | string arg = std::get<Literal>(_arguments.at(0)).value.str(); |
453 | 12.7k | if (arg.length() < 32) |
454 | 12.5k | arg.resize(32, 0); |
455 | 12.7k | if (fun == "datasize") |
456 | 9.12k | return u256(keccak256(arg)) & 0xfff; |
457 | 3.66k | else |
458 | 3.66k | { |
459 | | // Force different value than for datasize |
460 | 3.66k | arg[31]++; |
461 | 3.66k | arg[31]++; |
462 | 3.66k | return u256(keccak256(arg)) & 0xfff; |
463 | 3.66k | } |
464 | 12.7k | } |
465 | 2.27k | else if (fun == "datacopy") |
466 | 2.27k | { |
467 | | // This is identical to codecopy. |
468 | 2.27k | if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2))) |
469 | 1.11k | copyZeroExtended( |
470 | 1.11k | m_state.memory, |
471 | 1.11k | m_state.code, |
472 | 1.11k | size_t(_evaluatedArguments.at(0)), |
473 | 1.11k | size_t(_evaluatedArguments.at(1) & numeric_limits<size_t>::max()), |
474 | 1.11k | size_t(_evaluatedArguments.at(2)) |
475 | 1.11k | ); |
476 | 2.27k | return 0; |
477 | 2.27k | } |
478 | 0 | else |
479 | 2.27k | yulAssert(false, "Unknown builtin: " + fun); |
480 | 0 | return 0; |
481 | 15.0k | } |
482 | | |
483 | | |
484 | | bool EVMInstructionInterpreter::accessMemory(u256 const& _offset, u256 const& _size) |
485 | 391k | { |
486 | 391k | if (((_offset + _size) >= _offset) && ((_offset + _size + 0x1f) >= (_offset + _size))) |
487 | 382k | { |
488 | 382k | u256 newSize = (_offset + _size + 0x1f) & ~u256(0x1f); |
489 | 382k | m_state.msize = max(m_state.msize, newSize); |
490 | | // We only record accesses to contiguous memory chunks that are at most 0xffff bytes |
491 | | // in size and at an offset of at most numeric_limits<size_t>::max() - 0xffff |
492 | 382k | return _size <= 0xffff && _offset <= u256(numeric_limits<size_t>::max() - 0xffff); |
493 | 382k | } |
494 | 8.91k | else |
495 | 8.91k | m_state.msize = u256(-1); |
496 | | |
497 | 8.91k | return false; |
498 | 391k | } |
499 | | |
500 | | bytes EVMInstructionInterpreter::readMemory(u256 const& _offset, u256 const& _size) |
501 | 87.5k | { |
502 | 87.5k | yulAssert(_size <= 0xffff, "Too large read."); |
503 | 87.5k | bytes data(size_t(_size), uint8_t(0)); |
504 | 12.4M | for (size_t i = 0; i < data.size(); ++i) |
505 | 12.3M | data[i] = m_state.memory[_offset + i]; |
506 | 87.5k | return data; |
507 | 87.5k | } |
508 | | |
509 | | u256 EVMInstructionInterpreter::readMemoryWord(u256 const& _offset) |
510 | 78.6k | { |
511 | 78.6k | return u256(h256(readMemory(_offset, 32))); |
512 | 78.6k | } |
513 | | |
514 | | void EVMInstructionInterpreter::writeMemoryWord(u256 const& _offset, u256 const& _value) |
515 | 84.4k | { |
516 | 2.78M | for (size_t i = 0; i < 32; i++) |
517 | 2.70M | m_state.memory[_offset + i] = uint8_t((_value >> (8 * (31 - i))) & 0xff); |
518 | 84.4k | } |
519 | | |
520 | | |
521 | | void EVMInstructionInterpreter::logTrace( |
522 | | evmasm::Instruction _instruction, |
523 | | std::vector<u256> const& _arguments, |
524 | | bytes const& _data |
525 | | ) |
526 | 134k | { |
527 | 134k | logTrace( |
528 | 134k | evmasm::instructionInfo(_instruction).name, |
529 | 134k | SemanticInformation::memory(_instruction) == SemanticInformation::Effect::Write, |
530 | 134k | _arguments, |
531 | 134k | _data |
532 | 134k | ); |
533 | 134k | } |
534 | | |
535 | | void EVMInstructionInterpreter::logTrace( |
536 | | std::string const& _pseudoInstruction, |
537 | | bool _writesToMemory, |
538 | | std::vector<u256> const& _arguments, |
539 | | bytes const& _data |
540 | | ) |
541 | 134k | { |
542 | 134k | if (!(_writesToMemory && memWriteTracingDisabled())) |
543 | 49.5k | { |
544 | 49.5k | string message = _pseudoInstruction + "("; |
545 | 199k | for (size_t i = 0; i < _arguments.size(); ++i) |
546 | 150k | message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); |
547 | 49.5k | message += ")"; |
548 | 49.5k | if (!_data.empty()) |
549 | 165 | message += " [" + util::toHex(_data) + "]"; |
550 | 49.5k | m_state.trace.emplace_back(std::move(message)); |
551 | 49.5k | if (m_state.maxTraceSize > 0 && m_state.trace.size() >= m_state.maxTraceSize) |
552 | 129 | { |
553 | 129 | m_state.trace.emplace_back("Trace size limit reached."); |
554 | 129 | BOOST_THROW_EXCEPTION(TraceLimitReached()); |
555 | 129 | } |
556 | 49.5k | } |
557 | 134k | } |