Coverage Report

Created: 2026-06-30 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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