mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add bytecode optimizer fuzzer
This commit is contained in:
parent
1485374115
commit
295aef77a4
213
test/tools/ossfuzz/BytecodeOptimizerFuzzer.cpp
Normal file
213
test/tools/ossfuzz/BytecodeOptimizerFuzzer.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#include <test/tools/fuzzer_common.h>
|
||||
|
||||
#include <test/tools/ossfuzz/SolidityEvmoneInterface.h>
|
||||
|
||||
#include <test/tools/ossfuzz/ValueGenerator.h>
|
||||
|
||||
#include <test/TestCaseReader.h>
|
||||
|
||||
#include <libsolidity/util/ContractABIUtils.h>
|
||||
|
||||
#include <libyul/backends/evm/EVMCodeTransform.h>
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <evmone/evmone.h>
|
||||
|
||||
#include <abicoder.hpp>
|
||||
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
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<char const*>(_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<string, string> 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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
add_custom_target(ossfuzz)
|
||||
add_dependencies(ossfuzz
|
||||
solc_ossfuzz
|
||||
bytecode_optimizer_ossfuzz
|
||||
solc_mutator_ossfuzz
|
||||
const_opt_ossfuzz
|
||||
strictasm_diff_ossfuzz
|
||||
@ -35,6 +36,18 @@ if (OSSFUZZ)
|
||||
target_link_libraries(solc_ossfuzz PRIVATE libsolc evmasm evmc evmone-standalone abicoder gmp.a)
|
||||
set_target_properties(solc_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
add_executable(bytecode_optimizer_ossfuzz
|
||||
BytecodeOptimizerFuzzer.cpp
|
||||
ValueGenerator.cpp
|
||||
../fuzzer_common.cpp
|
||||
../../TestCaseReader.cpp
|
||||
../../EVMHost.cpp
|
||||
SolidityEvmoneInterface.cpp
|
||||
../../libsolidity/util/ContractABIUtils.cpp
|
||||
)
|
||||
target_link_libraries(bytecode_optimizer_ossfuzz PRIVATE libsolc evmasm evmc evmone-standalone abicoder gmp.a)
|
||||
set_target_properties(bytecode_optimizer_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
add_executable(solc_mutator_ossfuzz
|
||||
solc_ossfuzz.cpp
|
||||
../fuzzer_common.cpp
|
||||
|
||||
@ -219,15 +219,17 @@ void ValueGenerator::initialiseArray(
|
||||
TypeInfo& _typeInfo
|
||||
)
|
||||
{
|
||||
#if 0
|
||||
cout << "Init 1D array" << endl;
|
||||
cout << _typeInfo.value << endl;
|
||||
#endif
|
||||
_typeInfo.value += "[";
|
||||
std::string separator;
|
||||
for (size_t j = 0; j < _arrayInfo.numElements; j++)
|
||||
{
|
||||
_typeInfo.value += separator;
|
||||
if (_typeInfo.type == Type::Tuple) {
|
||||
cout << "Tuple inside array" << endl;
|
||||
// cout << "Tuple inside array" << endl;
|
||||
initialiseTuple(_typeInfo);
|
||||
}
|
||||
else
|
||||
@ -236,7 +238,9 @@ void ValueGenerator::initialiseArray(
|
||||
separator = ",";
|
||||
}
|
||||
_typeInfo.value += "]";
|
||||
#if 0
|
||||
cout << _typeInfo.value << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ValueGenerator::initialiseArray(
|
||||
@ -389,7 +393,7 @@ void ValueGenerator::typeHelper(Json::Value const& _type, TypeInfo& _typeInfo)
|
||||
if (_typeInfo.arrayInfo.empty())
|
||||
{
|
||||
if (_typeInfo.type == Type::Tuple) {
|
||||
cout << "Init tuple" << endl;
|
||||
// cout << "Init tuple" << endl;
|
||||
initialiseTuple(_typeInfo);
|
||||
}
|
||||
else
|
||||
@ -397,7 +401,7 @@ void ValueGenerator::typeHelper(Json::Value const& _type, TypeInfo& _typeInfo)
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Init array" << endl;
|
||||
// cout << "Init array" << endl;
|
||||
initialiseArray(_typeInfo.arrayInfo, _typeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user