diff --git a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp index bb2edf432..5e6acbb00 100644 --- a/test/tools/ossfuzz/SolidityEvmoneInterface.cpp +++ b/test/tools/ossfuzz/SolidityEvmoneInterface.cpp @@ -156,7 +156,7 @@ evmc::result EvmoneUtility::deployAndExecute( return callResult; } -optional EvmoneUtility::compileAndDeployLibrary() +optional EvmoneUtility::compileAndDeployLibrary() { solAssert(!m_libraryName.empty(), "SolidityEvmoneInterface: No library set."); m_compilationFramework.contractName(m_libraryName); @@ -171,10 +171,15 @@ optional EvmoneUtility::compileAndDeployLibrary() createResult.status_code == EVMC_SUCCESS, "SolidityEvmoneInterface: Library deployment failed" ); + auto libraryAt = EVMHost::convertFromEVMC(createResult.create_address); m_compilationFramework.libraryAddresses( - {{m_libraryName, EVMHost::convertFromEVMC(createResult.create_address)}} + {{m_libraryName, libraryAt}} ); - return createResult; + vector libraryFunctionSelectors; + for (auto const& function: compilationOutput->methodIdentifiersInContract) + libraryFunctionSelectors.push_back(function.asString()); + + return LibraryStatus{createResult.status_code, libraryAt, libraryFunctionSelectors}; } else return nullopt; @@ -187,7 +192,7 @@ optional EvmoneUtility::compileDeployAndExecute(string _fuzzIsabel { auto r = compileAndDeployLibrary(); if (!r.has_value()) - return r; + return nullopt; } // Stage 2: Compile, deploy, and execute contract, optionally using library // address map. diff --git a/test/tools/ossfuzz/SolidityEvmoneInterface.h b/test/tools/ossfuzz/SolidityEvmoneInterface.h index bc5385c8b..0fafd6632 100644 --- a/test/tools/ossfuzz/SolidityEvmoneInterface.h +++ b/test/tools/ossfuzz/SolidityEvmoneInterface.h @@ -218,8 +218,10 @@ public: /// identifiers for methods in @param _contractName. std::optional compileContract(); + using LibraryStatus = std::tuple>; + /// Compiles and deploys library on blockchain. - std::optional compileAndDeployLibrary(); + std::optional compileAndDeployLibrary(); private: diff --git a/test/tools/ossfuzz/solc_ossfuzz.cpp b/test/tools/ossfuzz/solc_ossfuzz.cpp index 6111865db..eed94a6a9 100644 --- a/test/tools/ossfuzz/solc_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_ossfuzz.cpp @@ -123,10 +123,12 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) methodName ); + optional libraryInfo; + if (!libraryName.empty()) { cout << "Deploying library" << endl; - auto l = evmoneUtil.compileAndDeployLibrary(); - if (!l.has_value()) + libraryInfo = evmoneUtil.compileAndDeployLibrary(); + if (!libraryInfo.has_value() || get<0>(libraryInfo.value()) != EVMC_SUCCESS) return 0; cout << "Deployed" << endl; } @@ -135,6 +137,11 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) for (auto const& account: hostContext.accounts) addressSelector[EVMHost::convertFromEVMC(account.first)] = {}; + // Add library functions to address selector + vector libraryFunctionSelectors = get<2>(libraryInfo.value()); + if (!libraryFunctionSelectors.empty()) + addressSelector[get<1>(libraryInfo.value())] = libraryFunctionSelectors; + auto compilerOutput = evmoneUtil.compileContract(); if (!compilerOutput.has_value()) return 0; @@ -183,17 +190,37 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) // Reset call state post old code gen run hostContext.reset(); addressSelector.clear(); + bool libraryFunctions = !libraryFunctionSelectors.empty(); + libraryFunctionSelectors.clear(); evmoneUtil.optSetting(compilerSetting); evmoneUtil.viaIR(true); + + optional libraryInfoNew; if (!libraryName.empty()) { - auto l = evmoneUtil.compileAndDeployLibrary(); - solAssert(l.has_value(), "Deploying library failed for the second time"); + libraryInfoNew = evmoneUtil.compileAndDeployLibrary(); + solAssert( + libraryInfoNew.has_value() && get<0>(libraryInfoNew.value()) == EVMC_SUCCESS, + "Deploying library failed for the second time" + ); } for (auto const& account: hostContext.accounts) addressSelector[EVMHost::convertFromEVMC(account.first)] = {}; + libraryFunctionSelectors = get<2>(libraryInfoNew.value()); + // Library functions in both runs should either be both empty or + // both non-empty. + solAssert( + ( + (libraryFunctions && !libraryFunctionSelectors.empty()) || + (!libraryFunctions && libraryFunctionSelectors.empty()) + ), + "Library function mismatch." + ); + if (!libraryFunctionSelectors.empty()) + addressSelector[get<1>(libraryInfoNew.value())] = libraryFunctionSelectors; + auto compilerOutputOpt = evmoneUtil.compileContract(); solAssert(compilerOutputOpt.has_value(), "Contract could not be optimised.");