/* 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; } } }