Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/test/tools/ossfuzz/SolidityEvmoneInterface.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 <test/tools/ossfuzz/SolidityEvmoneInterface.h>
20
21
#include <liblangutil/Exceptions.h>
22
#include <liblangutil/SourceReferenceFormatter.h>
23
24
#include <range/v3/algorithm/all_of.hpp>
25
#include <range/v3/span.hpp>
26
27
using namespace solidity::test::fuzzer;
28
using namespace solidity::frontend;
29
using namespace solidity::langutil;
30
using namespace solidity::util;
31
32
std::optional<CompilerOutput> SolidityCompilationFramework::compileContract()
33
661
{
34
661
  m_compiler.setSources(m_compilerInput.sourceCode);
35
661
  m_compiler.setLibraries(m_compilerInput.libraryAddresses);
36
661
  m_compiler.setEVMVersion(m_compilerInput.evmVersion);
37
661
  m_compiler.setOptimiserSettings(m_compilerInput.optimiserSettings);
38
661
  m_compiler.setViaIR(m_compilerInput.viaIR);
39
661
  if (!m_compiler.compile())
40
0
  {
41
0
    if (m_compilerInput.debugFailure)
42
0
    {
43
0
      std::cerr << "Compiling contract failed" << std::endl;
44
0
      std::cerr << SourceReferenceFormatter::formatErrorInformation(
45
0
        m_compiler.errors(),
46
0
        m_compiler
47
0
      );
48
0
    }
49
0
    return {};
50
0
  }
51
661
  else
52
661
  {
53
661
    std::string contractName;
54
661
    if (m_compilerInput.contractName.empty())
55
0
      contractName = m_compiler.lastContractName();
56
661
    else
57
661
      contractName = m_compilerInput.contractName;
58
661
    evmasm::LinkerObject obj = m_compiler.object(contractName);
59
661
    Json methodIdentifiers = m_compiler.interfaceSymbols(contractName)["methods"];
60
661
    return CompilerOutput{obj.bytecode, methodIdentifiers};
61
661
  }
62
661
}
63
64
bool EvmoneUtility::zeroWord(uint8_t const* _result, size_t _length)
65
661
{
66
661
  return _length == 32 &&
67
661
    ranges::all_of(
68
661
      ranges::span(_result, static_cast<long>(_length)),
69
21.1k
      [](uint8_t _v) { return _v == 0; });
70
661
}
71
72
evmc_message EvmoneUtility::initializeMessage(bytes const& _input)
73
1.32k
{
74
  // Zero initialize all message fields
75
1.32k
  evmc_message msg = {};
76
  // Gas available (value of type int64_t) is set to its maximum
77
  // value.
78
1.32k
  msg.gas = std::numeric_limits<int64_t>::max();
79
1.32k
  msg.input_data = _input.data();
80
1.32k
  msg.input_size = _input.size();
81
1.32k
  return msg;
82
1.32k
}
83
84
evmc::Result EvmoneUtility::executeContract(
85
  bytes const& _functionHash,
86
  evmc_address _deployedAddress
87
)
88
661
{
89
661
  evmc_message message = initializeMessage(_functionHash);
90
661
  message.recipient = _deployedAddress;
91
661
  message.code_address = _deployedAddress;
92
661
  message.kind = EVMC_CALL;
93
661
  return m_evmHost.call(message);
94
661
}
95
96
evmc::Result EvmoneUtility::deployContract(bytes const& _code)
97
661
{
98
661
  evmc_message message = initializeMessage(_code);
99
661
  message.kind = EVMC_CREATE;
100
661
  return m_evmHost.call(message);
101
661
}
102
103
evmc::Result EvmoneUtility::deployAndExecute(
104
  bytes const& _byteCode,
105
  std::string const& _hexEncodedInput
106
)
107
661
{
108
  // Deploy contract and signal failure if deploy failed
109
661
  evmc::Result createResult = deployContract(_byteCode);
110
661
  solAssert(
111
661
    createResult.status_code == EVMC_SUCCESS,
112
661
    "SolidityEvmoneInterface: Contract creation failed"
113
661
  );
114
115
  // Execute test function and signal failure if EVM reverted or
116
  // did not return expected output on successful execution.
117
661
  evmc::Result callResult = executeContract(
118
661
    util::fromHex(_hexEncodedInput),
119
661
    createResult.create_address
120
661
  );
121
122
  // We don't care about EVM One failures other than EVMC_REVERT
123
661
  solAssert(
124
661
    callResult.status_code != EVMC_REVERT,
125
661
    "SolidityEvmoneInterface: EVM One reverted"
126
661
  );
127
661
  return callResult;
128
661
}
129
130
evmc::Result EvmoneUtility::compileDeployAndExecute(std::string _fuzzIsabelle)
131
661
{
132
661
  std::map<std::string, h160> libraryAddressMap;
133
  // Stage 1: Compile and deploy library if present.
134
661
  if (!m_libraryName.empty())
135
0
  {
136
0
    m_compilationFramework.contractName(m_libraryName);
137
0
    auto compilationOutput = m_compilationFramework.compileContract();
138
0
    solAssert(compilationOutput.has_value(), "Compiling library failed");
139
0
    CompilerOutput cOutput = compilationOutput.value();
140
    // Deploy contract and signal failure if deploy failed
141
0
    evmc::Result createResult = deployContract(cOutput.byteCode);
142
0
    solAssert(
143
0
      createResult.status_code == EVMC_SUCCESS,
144
0
      "SolidityEvmoneInterface: Library deployment failed"
145
0
    );
146
0
    libraryAddressMap[m_libraryName] = EVMHost::convertFromEVMC(createResult.create_address);
147
0
    m_compilationFramework.libraryAddresses(libraryAddressMap);
148
0
  }
149
150
  // Stage 2: Compile, deploy, and execute contract, optionally using library
151
  // address map.
152
661
  m_compilationFramework.contractName(m_contractName);
153
661
  auto cOutput = m_compilationFramework.compileContract();
154
661
  solAssert(cOutput.has_value(), "Compiling contract failed");
155
661
  solAssert(
156
661
    !cOutput->byteCode.empty() && !cOutput->methodIdentifiersInContract.empty(),
157
661
    "SolidityEvmoneInterface: Invalid compilation output."
158
661
  );
159
160
661
  std::string methodName;
161
661
  if (!_fuzzIsabelle.empty())
162
    // TODO: Remove this once a cleaner solution is found for querying
163
    // isabelle test entry point. At the moment, we are sure that the
164
    // entry point is the second method in the contract (hence the ++)
165
    // but not its name.
166
123
    methodName = (++cOutput->methodIdentifiersInContract.begin())->get<std::string>() +
167
123
      _fuzzIsabelle.substr(2, _fuzzIsabelle.size());
168
538
  else
169
538
    methodName = cOutput->methodIdentifiersInContract[m_methodName].get<std::string>();
170
171
661
  return deployAndExecute(
172
661
    cOutput->byteCode,
173
661
    methodName
174
661
  );
175
661
}
176
177
std::optional<CompilerOutput> EvmoneUtility::compileContract()
178
0
{
179
0
  try
180
0
  {
181
0
    return m_compilationFramework.compileContract();
182
0
  }
183
0
  catch (evmasm::StackTooDeepException const&)
184
0
  {
185
0
    return {};
186
0
  }
187
0
}