Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/test/tools/yulInterpreter/Interpreter.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
 * Yul interpreter.
20
 */
21
22
#include <test/tools/yulInterpreter/Interpreter.h>
23
24
#include <test/tools/yulInterpreter/EVMInstructionInterpreter.h>
25
26
#include <libyul/AST.h>
27
#include <libyul/Dialect.h>
28
#include <libyul/Utilities.h>
29
#include <libyul/backends/evm/EVMDialect.h>
30
31
#include <liblangutil/Exceptions.h>
32
33
#include <libsolutil/FixedHash.h>
34
35
#include <range/v3/view/reverse.hpp>
36
37
#include <ostream>
38
#include <variant>
39
40
using namespace solidity;
41
using namespace solidity::yul;
42
using namespace solidity::yul::test;
43
44
using solidity::util::h256;
45
46
void InterpreterState::dumpStorage(std::ostream& _out) const
47
99.5k
{
48
99.5k
  for (auto const& [slot, value]: storage)
49
149k
    if (value != h256{})
50
85.8k
      _out << "  " << slot.hex() << ": " << value.hex() << std::endl;
51
99.5k
}
52
53
void InterpreterState::dumpTransientStorage(std::ostream& _out) const
54
99.5k
{
55
99.5k
  for (auto const& [slot, value]: transientStorage)
56
17.4k
    if (value != h256{})
57
6.53k
      _out << "  " << slot.hex() << ": " << value.hex() << std::endl;
58
99.5k
}
59
60
void InterpreterState::dumpTraceAndState(std::ostream& _out, bool _disableMemoryTrace) const
61
99.5k
{
62
99.5k
  _out << "Trace:" << std::endl;
63
99.5k
  for (auto const& line: trace)
64
80.5k
    _out << "  " << line << std::endl;
65
99.5k
  if (!_disableMemoryTrace)
66
0
  {
67
0
    _out << "Memory dump:\n";
68
0
    std::map<u256, u256> words;
69
0
    for (auto const& [offset, value]: memory)
70
0
      words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * static_cast<size_t>(offset % 0x20));
71
0
    for (auto const& [offset, value]: words)
72
0
      if (value != 0)
73
0
        _out << "  " << std::uppercase << std::hex << std::setw(4) << offset << ": " << h256(value).hex() << std::endl;
74
0
  }
75
99.5k
  _out << "Storage dump:" << std::endl;
76
99.5k
  dumpStorage(_out);
77
78
99.5k
  _out << "Transient storage dump:" << std::endl;
79
99.5k
  dumpTransientStorage(_out);
80
81
99.5k
  if (!calldata.empty())
82
99.5k
  {
83
99.5k
    _out << "Calldata dump:";
84
85
6.47M
    for (size_t offset = 0; offset < calldata.size(); ++offset)
86
6.37M
      if (calldata[offset] != 0)
87
6.37M
      {
88
6.37M
        if (offset % 32 == 0)
89
199k
          _out <<
90
199k
            std::endl <<
91
199k
            "  " <<
92
199k
            std::uppercase <<
93
199k
            std::hex <<
94
199k
            std::setfill(' ') <<
95
199k
            std::setw(4) <<
96
199k
            offset <<
97
199k
            ": ";
98
99
6.37M
        _out <<
100
6.37M
          std::hex <<
101
6.37M
          std::setw(2) <<
102
6.37M
          std::setfill('0') <<
103
6.37M
          static_cast<int>(calldata[offset]);
104
6.37M
      }
105
106
99.5k
    _out << std::endl;
107
99.5k
  }
108
99.5k
}
109
110
void Interpreter::run(
111
  InterpreterState& _state,
112
  AST const& _ast,
113
  bool _disableExternalCalls,
114
  bool _disableMemoryTrace
115
)
116
99.5k
{
117
99.5k
  Scope scope;
118
99.5k
  Interpreter{_state, _ast.dialect(), scope, _disableExternalCalls, _disableMemoryTrace}(_ast.root());
119
99.5k
}
120
121
void Interpreter::operator()(ExpressionStatement const& _expressionStatement)
122
729k
{
123
729k
  evaluateMulti(_expressionStatement.expression);
124
729k
}
125
126
void Interpreter::operator()(Assignment const& _assignment)
127
212k
{
128
212k
  solAssert(_assignment.value, "");
129
212k
  std::vector<u256> values = evaluateMulti(*_assignment.value);
130
212k
  solAssert(values.size() == _assignment.variableNames.size(), "");
131
421k
  for (size_t i = 0; i < values.size(); ++i)
132
209k
  {
133
209k
    YulName varName = _assignment.variableNames.at(i).name;
134
209k
    solAssert(m_variables.count(varName), "");
135
209k
    m_variables[varName] = values.at(i);
136
209k
  }
137
212k
}
138
139
void Interpreter::operator()(VariableDeclaration const& _declaration)
140
341k
{
141
341k
  std::vector<u256> values(_declaration.variables.size(), 0);
142
341k
  if (_declaration.value)
143
294k
    values = evaluateMulti(*_declaration.value);
144
145
341k
  solAssert(values.size() == _declaration.variables.size(), "");
146
778k
  for (size_t i = 0; i < values.size(); ++i)
147
436k
  {
148
436k
    YulName varName = _declaration.variables.at(i).name;
149
436k
    solAssert(!m_variables.count(varName), "");
150
436k
    m_variables[varName] = values.at(i);
151
436k
    m_scope->names.emplace(varName, nullptr);
152
436k
  }
153
341k
}
154
155
void Interpreter::operator()(If const& _if)
156
69.1k
{
157
69.1k
  solAssert(_if.condition, "");
158
69.1k
  if (evaluate(*_if.condition) != 0)
159
56.7k
    (*this)(_if.body);
160
69.1k
}
161
162
void Interpreter::operator()(Switch const& _switch)
163
63.3k
{
164
63.3k
  solAssert(_switch.expression, "");
165
63.3k
  u256 val = evaluate(*_switch.expression);
166
63.3k
  solAssert(!_switch.cases.empty(), "");
167
63.3k
  for (auto const& c: _switch.cases)
168
    // Default case has to be last.
169
140k
    if (!c.value || evaluate(*c.value) == val)
170
59.4k
    {
171
59.4k
      (*this)(c.body);
172
59.4k
      break;
173
59.4k
    }
174
63.3k
}
175
176
void Interpreter::operator()(FunctionDefinition const&)
177
100k
{
178
100k
}
179
180
void Interpreter::operator()(ForLoop const& _forLoop)
181
106k
{
182
106k
  solAssert(_forLoop.condition, "");
183
184
106k
  enterScope(_forLoop.pre);
185
106k
  ScopeGuard g([this]{ leaveScope(); });
186
187
106k
  for (auto const& statement: _forLoop.pre.statements)
188
62.9k
  {
189
62.9k
    visit(statement);
190
62.9k
    if (m_state.controlFlowState == ControlFlowState::Leave)
191
582
      return;
192
62.9k
  }
193
379k
  while (evaluate(*_forLoop.condition) != 0)
194
289k
  {
195
    // Increment step for each loop iteration for loops with
196
    // an empty body and post blocks to prevent a deadlock.
197
289k
    if (_forLoop.body.statements.size() == 0 && _forLoop.post.statements.size() == 0)
198
12.6k
      incrementStep();
199
200
289k
    m_state.controlFlowState = ControlFlowState::Default;
201
289k
    (*this)(_forLoop.body);
202
289k
    if (m_state.controlFlowState == ControlFlowState::Break || m_state.controlFlowState == ControlFlowState::Leave)
203
11.4k
      break;
204
205
278k
    m_state.controlFlowState = ControlFlowState::Default;
206
278k
    (*this)(_forLoop.post);
207
278k
    if (m_state.controlFlowState == ControlFlowState::Leave)
208
4.43k
      break;
209
278k
  }
210
105k
  if (m_state.controlFlowState != ControlFlowState::Leave)
211
86.4k
    m_state.controlFlowState = ControlFlowState::Default;
212
105k
}
213
214
void Interpreter::operator()(Break const&)
215
7.55k
{
216
7.55k
  m_state.controlFlowState = ControlFlowState::Break;
217
7.55k
}
218
219
void Interpreter::operator()(Continue const&)
220
33.9k
{
221
33.9k
  m_state.controlFlowState = ControlFlowState::Continue;
222
33.9k
}
223
224
void Interpreter::operator()(Leave const&)
225
34.5k
{
226
34.5k
  m_state.controlFlowState = ControlFlowState::Leave;
227
34.5k
}
228
229
void Interpreter::operator()(Block const& _block)
230
1.18M
{
231
1.18M
  enterScope(_block);
232
  // Register functions.
233
1.18M
  for (auto const& statement: _block.statements)
234
2.30M
    if (std::holds_alternative<FunctionDefinition>(statement))
235
129k
    {
236
129k
      FunctionDefinition const& funDef = std::get<FunctionDefinition>(statement);
237
129k
      m_scope->names.emplace(funDef.name, &funDef);
238
129k
    }
239
240
1.18M
  for (auto const& statement: _block.statements)
241
1.80M
  {
242
1.80M
    incrementStep();
243
1.80M
    visit(statement);
244
1.80M
    if (m_state.controlFlowState != ControlFlowState::Default)
245
104k
      break;
246
1.80M
  }
247
248
1.18M
  leaveScope();
249
1.18M
}
250
251
u256 Interpreter::evaluate(Expression const& _expression)
252
585k
{
253
585k
  ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace);
254
585k
  ev.visit(_expression);
255
585k
  return ev.value();
256
585k
}
257
258
std::vector<u256> Interpreter::evaluateMulti(Expression const& _expression)
259
1.23M
{
260
1.23M
  ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace);
261
1.23M
  ev.visit(_expression);
262
1.23M
  return ev.values();
263
1.23M
}
264
265
void Interpreter::enterScope(Block const& _block)
266
1.29M
{
267
1.29M
  if (!m_scope->subScopes.count(&_block))
268
611k
    m_scope->subScopes[&_block] = std::make_unique<Scope>(Scope{
269
611k
      {},
270
611k
      {},
271
611k
      m_scope
272
611k
    });
273
1.29M
  m_scope = m_scope->subScopes[&_block].get();
274
1.29M
}
275
276
void Interpreter::leaveScope()
277
1.16M
{
278
1.16M
  for (auto const& [var, funDeclaration]: m_scope->names)
279
483k
    if (!funDeclaration)
280
397k
      m_variables.erase(var);
281
1.16M
  m_scope = m_scope->parent;
282
1.16M
  yulAssert(m_scope, "");
283
1.16M
}
284
285
void Interpreter::incrementStep()
286
1.81M
{
287
1.81M
  m_state.numSteps++;
288
1.81M
  if (m_state.maxSteps > 0 && m_state.numSteps >= m_state.maxSteps)
289
3.80k
  {
290
3.80k
    m_state.trace.emplace_back("Interpreter execution step limit reached.");
291
3.80k
    BOOST_THROW_EXCEPTION(StepLimitReached());
292
3.80k
  }
293
1.81M
}
294
295
void ExpressionEvaluator::operator()(Literal const& _literal)
296
4.72M
{
297
4.72M
  incrementStep();
298
4.72M
  setValue(_literal.value.value());
299
4.72M
}
300
301
void ExpressionEvaluator::operator()(Identifier const& _identifier)
302
907k
{
303
907k
  solAssert(m_variables.count(_identifier.name), "");
304
907k
  incrementStep();
305
907k
  setValue(m_variables.at(_identifier.name));
306
907k
}
307
308
void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
309
4.21M
{
310
4.21M
  std::vector<std::optional<LiteralKind>> const* literalArguments = nullptr;
311
4.21M
  if (BuiltinFunction const* builtin = resolveBuiltinFunction(_funCall.functionName, m_dialect))
312
3.96M
    if (!builtin->literalArguments.empty())
313
75.1k
      literalArguments = &builtin->literalArguments;
314
4.21M
  evaluateArgs(_funCall.arguments, literalArguments);
315
316
4.21M
  if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
317
4.12M
  {
318
4.12M
    if (BuiltinFunctionForEVM const* fun = resolveBuiltinFunctionForEVM(_funCall.functionName, *dialect))
319
3.87M
    {
320
3.87M
      EVMInstructionInterpreter interpreter(dialect->evmVersion(), m_state, m_disableMemoryTrace);
321
322
3.87M
      u256 const value = interpreter.evalBuiltin(*fun, _funCall.arguments, values());
323
324
3.87M
      if (
325
3.87M
        !m_disableExternalCalls &&
326
0
        fun->instruction &&
327
0
        evmasm::isCallInstruction(*fun->instruction)
328
3.87M
      )
329
0
        runExternalCall(*fun->instruction);
330
331
3.87M
      setValue(value);
332
3.87M
      return;
333
3.87M
    }
334
4.12M
  }
335
336
334k
  yulAssert(!isBuiltinFunctionCall(_funCall));
337
334k
  Scope* scope = &m_scope;
338
4.37M
  for (; scope; scope = scope->parent)
339
4.28M
    if (scope->names.count(std::get<Identifier>(_funCall.functionName).name))
340
242k
      break;
341
334k
  yulAssert(scope, "");
342
343
334k
  FunctionDefinition const* fun = scope->names.at(std::get<Identifier>(_funCall.functionName).name);
344
334k
  yulAssert(fun, "Function not found.");
345
334k
  yulAssert(m_values.size() == fun->parameters.size(), "");
346
334k
  std::map<YulName, u256> variables;
347
849k
  for (size_t i = 0; i < fun->parameters.size(); ++i)
348
515k
    variables[fun->parameters.at(i).name] = m_values.at(i);
349
657k
  for (size_t i = 0; i < fun->returnVariables.size(); ++i)
350
323k
    variables[fun->returnVariables.at(i).name] = 0;
351
352
334k
  m_state.controlFlowState = ControlFlowState::Default;
353
334k
  std::unique_ptr<Interpreter> interpreter = makeInterpreterCopy(std::move(variables));
354
334k
  (*interpreter)(fun->body);
355
334k
  m_state.controlFlowState = ControlFlowState::Default;
356
357
334k
  m_values.clear();
358
334k
  for (auto const& retVar: fun->returnVariables)
359
143k
    m_values.emplace_back(interpreter->valueOfVariable(retVar.name));
360
334k
}
361
362
u256 ExpressionEvaluator::value() const
363
8.58M
{
364
8.58M
  solAssert(m_values.size() == 1, "");
365
8.58M
  return m_values.front();
366
8.58M
}
367
368
void ExpressionEvaluator::setValue(u256 _value)
369
9.50M
{
370
9.50M
  m_values.clear();
371
9.50M
  m_values.emplace_back(std::move(_value));
372
9.50M
}
373
374
void ExpressionEvaluator::evaluateArgs(
375
  std::vector<Expression> const& _expr,
376
  std::vector<std::optional<LiteralKind>> const* _literalArguments
377
)
378
4.21M
{
379
4.21M
  incrementStep();
380
4.21M
  std::vector<u256> values;
381
4.21M
  size_t i = 0;
382
  /// Function arguments are evaluated in reverse.
383
4.21M
  for (auto const& expr: _expr | ranges::views::reverse)
384
8.09M
  {
385
8.09M
    if (!_literalArguments || !_literalArguments->at(_expr.size() - i - 1))
386
8.02M
      visit(expr);
387
75.1k
    else
388
75.1k
    {
389
75.1k
      if (std::get<Literal>(expr).value.unlimited())
390
17.0k
      {
391
17.0k
        yulAssert(std::get<Literal>(expr).kind == LiteralKind::String);
392
17.0k
        m_values = {0xdeadbeef};
393
17.0k
      }
394
58.0k
      else
395
58.0k
        m_values = {std::get<Literal>(expr).value.value()};
396
75.1k
    }
397
398
8.09M
    values.push_back(value());
399
8.09M
    ++i;
400
8.09M
  }
401
4.21M
  m_values = std::move(values);
402
4.21M
  std::reverse(m_values.begin(), m_values.end());
403
4.21M
}
404
405
void ExpressionEvaluator::incrementStep()
406
9.84M
{
407
9.84M
  m_nestingLevel++;
408
9.84M
  if (m_state.maxExprNesting > 0 && m_nestingLevel > m_state.maxExprNesting)
409
358
  {
410
358
    m_state.trace.emplace_back("Maximum expression nesting level reached.");
411
358
    BOOST_THROW_EXCEPTION(ExpressionNestingLimitReached());
412
358
  }
413
9.84M
}
414
415
void ExpressionEvaluator::runExternalCall(evmasm::Instruction _instruction)
416
0
{
417
0
  u256 memOutOffset = 0;
418
0
  u256 memOutSize = 0;
419
0
  u256 callvalue = 0;
420
0
  u256 memInOffset = 0;
421
0
  u256 memInSize = 0;
422
423
  // Setup memOut* values
424
0
  if (
425
0
    _instruction == evmasm::Instruction::CALL ||
426
0
    _instruction == evmasm::Instruction::CALLCODE
427
0
  )
428
0
  {
429
0
    memOutOffset = values()[5];
430
0
    memOutSize = values()[6];
431
0
    callvalue = values()[2];
432
0
    memInOffset = values()[3];
433
0
    memInSize = values()[4];
434
0
  }
435
0
  else if (
436
0
    _instruction == evmasm::Instruction::DELEGATECALL ||
437
0
    _instruction == evmasm::Instruction::STATICCALL
438
0
  )
439
0
  {
440
0
    memOutOffset = values()[4];
441
0
    memOutSize = values()[5];
442
0
    memInOffset = values()[2];
443
0
    memInSize = values()[3];
444
0
  }
445
0
  else
446
0
    yulAssert(false);
447
448
  // Don't execute external call if it isn't our own address
449
0
  if (values()[1] != util::h160::Arith(m_state.address))
450
0
    return;
451
452
0
  Scope tmpScope;
453
0
  InterpreterState tmpState;
454
0
  tmpState.calldata = m_state.readMemory(memInOffset, memInSize);
455
0
  tmpState.callvalue = callvalue;
456
0
  tmpState.numInstance = m_state.numInstance + 1;
457
458
0
  yulAssert(tmpState.numInstance < 1024, "Detected more than 1024 recursive calls, aborting...");
459
460
  // Create new interpreter for the called contract
461
0
  std::unique_ptr<Interpreter> newInterpreter = makeInterpreterNew(tmpState, tmpScope);
462
463
0
  Scope* abstractRootScope = &m_scope;
464
0
  Scope* fileScope = nullptr;
465
0
  Block const* ast = nullptr;
466
467
  // Find file scope
468
0
  while (abstractRootScope->parent)
469
0
  {
470
0
    fileScope = abstractRootScope;
471
0
    abstractRootScope = abstractRootScope->parent;
472
0
  }
473
474
  // Get AST for file scope
475
0
  for (auto&& [block, scope]: abstractRootScope->subScopes)
476
0
    if (scope.get() == fileScope)
477
0
    {
478
0
      ast = block;
479
0
      break;
480
0
    }
481
482
0
  yulAssert(ast);
483
484
0
  try
485
0
  {
486
0
    (*newInterpreter)(*ast);
487
0
  }
488
0
  catch (ExplicitlyTerminatedWithReturn const&)
489
0
  {
490
    // Copy return data to our memory
491
0
    copyZeroExtended(
492
0
      m_state.memory,
493
0
      newInterpreter->returnData(),
494
0
      memOutOffset.convert_to<size_t>(),
495
0
      0,
496
0
      memOutSize.convert_to<size_t>()
497
0
    );
498
0
    m_state.returndata = newInterpreter->returnData();
499
0
  }
500
0
}