diff --git a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp index 63bf7873f..bb2edf432 100644 --- a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp +++ b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp @@ -33,6 +33,8 @@ using namespace std; optional SolidityCompilationFramework::compileContract() { + // Reset since compiler stack may be called multiple times. + m_compiler.reset(true); m_compiler.setSources(m_compilerInput.sourceCode); m_compiler.setLibraries(m_compilerInput.libraryAddresses); m_compiler.setEVMVersion(m_compilerInput.evmVersion); @@ -84,7 +86,7 @@ optional SolidityCompilationFramework::randomFunction(size_t _seed) else { uniform_int_distribution d(0, contractABI.size() - 1); - minstd_rand r(_seed); + mt19937_64 r(_seed); return contractABI[d(r)]; } } diff --git a/test/tools/ossfuzz/ValueGenerator.cpp b/test/tools/ossfuzz/ValueGenerator.cpp index 248a8010a..2110ad2c9 100644 --- a/test/tools/ossfuzz/ValueGenerator.cpp +++ b/test/tools/ossfuzz/ValueGenerator.cpp @@ -152,8 +152,30 @@ string fixedBytes( std::string ValueGenerator::addressLiteral() { - std::uniform_int_distribution dist(0, m_addresses.size() - 1); - return "0x" + m_addresses[dist(m_rand)].hex(); + auto iter = m_addressSelector.begin(); + std::uniform_int_distribution dist(0, m_addressSelector.size() - 1); + std::advance(iter, dist(m_rand)); + return "0x" + iter->first.hex(); +} + +std::string ValueGenerator::functionLiteral() +{ + std::string contractAddress; + std::string functionSelector; + for (auto const& item: m_addressSelector) + if (!item.second.empty()) + { + contractAddress = "0x" + item.first.hex(); + auto selectors = item.second; + std::uniform_int_distribution dist(0, selectors.size() - 1); + functionSelector = "0x" + selectors[dist(m_rand)]; + return contractAddress + ":" + functionSelector; + } + // If no function found, simply output a (valid address, invalid function) pair. + return addressLiteral() + + ":" + + "0x" + + fixedBytes(static_cast(FixedBytesWidth::Bytes4), m_rand(), true); } void ValueGenerator::initialiseType(TypeInfo& _t) @@ -186,10 +208,7 @@ void ValueGenerator::initialiseType(TypeInfo& _t) _t.value += addressLiteral(); break; case Type::Function: - _t.value += addressLiteral() + - ":" + - "0x" + - fixedBytes(static_cast(FixedBytesWidth::Bytes4), m_rand(), true); + _t.value += functionLiteral(); break; default: solAssert(false, "Value Generator: Invalid value type."); diff --git a/test/tools/ossfuzz/ValueGenerator.h b/test/tools/ossfuzz/ValueGenerator.h index 30d0bf826..aa62efe2a 100644 --- a/test/tools/ossfuzz/ValueGenerator.h +++ b/test/tools/ossfuzz/ValueGenerator.h @@ -137,35 +137,13 @@ public: explicit ValueGenerator( Json::Value const& _type, unsigned _seed, - std::vector _addresses + std::map> _addressSelectors ): m_rand(_seed), m_type(_type), m_bernoulli(0.5), - m_addresses(std::move(_addresses)) + m_addressSelector(std::move(_addressSelectors)) {} - void boolean() - { - m_stream << (m_bernoulli(m_rand) ? "true" : "false"); - } - void string() - { - m_stream << "hello"; - } - void bytes() - { - m_stream << "0x1234"; - } - void function(); - void fixedbytes() - { - - } - void address(); - void integer() - { - - } void typeHelper(Json::Value const& _type, TypeInfo& _typeInfo); TypeInfo type(Json::Value const& _type); void tuple(Json::Value const& _tuple, TypeInfo& _typeInfo); @@ -181,10 +159,11 @@ public: TypeInfo& _typeInfo ); std::string addressLiteral(); + std::string contractAddress(); + std::string functionLiteral(); private: - std::ostringstream m_stream; std::mt19937_64 m_rand; Json::Value const& m_type; std::bernoulli_distribution m_bernoulli; - std::vector m_addresses; + std::map> m_addressSelector; }; diff --git a/test/tools/ossfuzz/solc_ossfuzz.cpp b/test/tools/ossfuzz/solc_ossfuzz.cpp index c85019120..6111865db 100644 --- a/test/tools/ossfuzz/solc_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_ossfuzz.cpp @@ -54,7 +54,7 @@ namespace { string abiEncoding( Json::Value const& _functionABI, - vector _addressLiterals, + map> _addressSelectors, Json::Value const& _methodIdentifiers ) { @@ -63,7 +63,7 @@ string abiEncoding( tie(abiTypeString, abiValueString) = ValueGenerator{ _functionABI["inputs"], 0, - _addressLiterals + _addressSelectors }.type(); string encodedData; // A function with inputs must contain type names within @@ -131,13 +131,10 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) cout << "Deployed" << endl; } - vector addressLiterals; + map> addressSelector; for (auto const& account: hostContext.accounts) - addressLiterals.push_back(EVMHost::convertFromEVMC(account.first)); + addressSelector[EVMHost::convertFromEVMC(account.first)] = {}; - hostContext.reset(); - evmoneUtil.reset(true); - evmoneUtil.optSetting(compilerSetting); auto compilerOutput = evmoneUtil.compileContract(); if (!compilerOutput.has_value()) return 0; @@ -150,10 +147,15 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) if (deployResult.status_code != EVMC_SUCCESS) return 0; - // Add deployed contract to list of address literals. - addressLiterals.push_back(EVMHost::convertFromEVMC(deployResult.create_address)); + // Record function selectors in contract + vector functionSelectors; + for (auto const& item: compilerOutput->methodIdentifiersInContract) + functionSelectors.push_back(item.asString()); - string encodedData = abiEncoding(r.value(), addressLiterals, + // Add deployed contract to list of address literals. + addressSelector[EVMHost::convertFromEVMC(deployResult.create_address)] = functionSelectors; + + string encodedData = abiEncoding(r.value(), addressSelector, compilerOutput->methodIdentifiersInContract); auto callResult = evmoneUtil.executeContract( solidity::util::fromHex(encodedData), @@ -177,13 +179,21 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) compilerSetting.runYulOptimiser = true; compilerSetting.optimizeStackAllocation = true; + + // Reset call state post old code gen run hostContext.reset(); - // Remove contract compiled via old code gen from list of address - // literals. - addressLiterals.pop_back(); - evmoneUtil.reset(true); + addressSelector.clear(); evmoneUtil.optSetting(compilerSetting); evmoneUtil.viaIR(true); + if (!libraryName.empty()) + { + auto l = evmoneUtil.compileAndDeployLibrary(); + solAssert(l.has_value(), "Deploying library failed for the second time"); + } + + for (auto const& account: hostContext.accounts) + addressSelector[EVMHost::convertFromEVMC(account.first)] = {}; + auto compilerOutputOpt = evmoneUtil.compileContract(); solAssert(compilerOutputOpt.has_value(), "Contract could not be optimised."); @@ -192,8 +202,9 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) "Contract compiled via new code gen could not be deployed."); // Add address literal of contract compiled via Yul IR. - addressLiterals.push_back(EVMHost::convertFromEVMC(deployResultOpt.create_address)); - string encodedDataIR = abiEncoding(r.value(), addressLiterals, + addressSelector[EVMHost::convertFromEVMC(deployResultOpt.create_address)] = functionSelectors; + + string encodedDataIR = abiEncoding(r.value(), addressSelector, compilerOutput->methodIdentifiersInContract); auto callResultOpt = evmoneUtil.executeContract(