/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see .
*/
// SPDX-License-Identifier: GPL-3.0
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace solidity::frontend::test;
using namespace solidity::frontend;
using namespace solidity::test::fuzzer;
using namespace solidity::langutil;
using namespace solidity::test;
using namespace std;
// Prototype as we can't use the FuzzerInterface.h header.
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size);
static evmc::VM evmone = evmc::VM{evmc_create_evmone()};
static constexpr size_t abiCoderHeapSize = 1024 * 512;
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
{
// if (_size <= 600)
{
string input(reinterpret_cast(_data), _size);
regex re = regex("library\\s*(\\w+)\\s*\\{");
smatch matches;
std::string libraryName;
auto match = regex_search(input, matches, re);
if (match && matches[1].matched)
libraryName = matches[1].str();
map sourceCode;
try
{
EVMVersion version;
EVMHost hostContext(version, evmone);
TestCaseReader t = TestCaseReader(std::istringstream(input));
sourceCode = t.sources().sources;
string contractName;
string methodName;
auto compilerSetting = OptimiserSettings::none();
CompilerInput cInput = {
version,
sourceCode,
contractName,
compilerSetting,
{},
true,
false
};
EvmoneUtility evmoneUtil(
hostContext,
cInput,
contractName,
libraryName,
methodName
);
if (!libraryName.empty())
{
cout << "Deploying library" << endl;
auto l = evmoneUtil.compileAndDeployLibrary();
if (!l.has_value())
return 0;
cout << "Deployed" << endl;
}
hostContext.reset();
evmoneUtil.reset(true);
evmoneUtil.optSetting(compilerSetting);
auto compilerOutput = evmoneUtil.compileContract();
if (!compilerOutput.has_value())
return 0;
auto r = evmoneUtil.randomFunction(_size);
if (!r.has_value())
return 0;
auto x = ValueGenerator{r.value()["inputs"], 0}.type();
bool encodeStatus;
string encodedData;
bool functionWithInputs = x.first != "()";
auto sig = r.value()["name"].asString() + x.first;
cout << sig << endl;
if (functionWithInputs)
{
abicoder::ABICoder coder(abiCoderHeapSize);
auto s = coder.encode(x.first, x.second);
encodeStatus = s.first;
encodedData = s.second;
solAssert(encodeStatus, "Isabelle coder: failed.");
}
auto deployResult = evmoneUtil.deployContract(compilerOutput->byteCode);
if (deployResult.status_code != EVMC_SUCCESS)
return 0;
auto methodSig = compilerOutput->methodIdentifiersInContract[sig].asString();
if (functionWithInputs)
methodSig += encodedData.substr(2, encodedData.size());
auto callResult = evmoneUtil.executeContract(
solidity::util::fromHex(methodSig),
deployResult.create_address
);
if (callResult.status_code != EVMC_SUCCESS)
{
cout << "Unoptimised call failed with status code: "
<< callResult.status_code
<< endl;
return 0;
}
solidity::bytes result;
for (size_t i = 0; i < callResult.output_size; i++)
result.push_back(callResult.output_data[i]);
cout << solidity::util::toHex(result) << endl;
EVMHostPrinter p(hostContext, deployResult.create_address);
ostringstream oldCodeGen;
oldCodeGen << p.state();
compilerSetting = OptimiserSettings::standard();
hostContext.reset();
evmoneUtil.reset(true);
evmoneUtil.optSetting(compilerSetting);
auto compilerOutputOpt = evmoneUtil.compileContract();
solAssert(compilerOutputOpt.has_value(), "Contract could not be optimised.");
auto deployResultOpt = evmoneUtil.deployContract(compilerOutputOpt->byteCode);
solAssert(deployResultOpt.status_code == EVMC_SUCCESS, "Contract compiled via old optimiser could not be deployed.");
auto callResultOpt = evmoneUtil.executeContract(
solidity::util::fromHex(methodSig),
deployResultOpt.create_address
);
solAssert(callResultOpt.status_code == EVMC_SUCCESS, "Old code gen optimised contract call failed.");
solidity::bytes resultOpt;
for (size_t i = 0; i < callResultOpt.output_size; i++)
resultOpt.push_back(callResultOpt.output_data[i]);
cout << solidity::util::toHex(resultOpt) << endl;
solAssert(result == resultOpt, "Unoptimised and optimised call results do not match.");
EVMHostPrinter pOpt(hostContext, deployResultOpt.create_address);
ostringstream newCodeGen;
newCodeGen << pOpt.state();
cout << oldCodeGen.str() << endl;
cout << newCodeGen.str() << endl;
solAssert(oldCodeGen.str() == newCodeGen.str(), "Old and new code gen state do not match.");
return 0;
}
catch (runtime_error const&)
{
cout << "Runtime error!" << endl;
return 0;
}
catch (solidity::langutil::UnimplementedFeatureError const&)
{
cout << "Unimplemented feature!" << endl;
return 0;
}
catch (solidity::langutil::CompilerError const& _e)
{
cout << "Compiler error!" << endl;
cout << _e.what() << endl;
return 0;
}
catch (solidity::yul::StackTooDeepError const&)
{
cout << "Stack too deep" << endl;
return 0;
}
}
}