diff --git a/test/tools/ossfuzz/SolProtoAdaptor.cpp b/test/tools/ossfuzz/SolProtoAdaptor.cpp index 407894ac8..3696d1601 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.cpp +++ b/test/tools/ossfuzz/SolProtoAdaptor.cpp @@ -476,6 +476,47 @@ interface is { .render(); } +bool SolContract::validTest() const +{ + return m_contractFunctionMap.size() > 0; +} + +tuple SolContract::pseudoRandomTest() +{ + solAssert(m_contractFunctionMap.size() > 0, "Sol proto adaptor: Empty contract map"); + string chosenContractName{}; + string chosenFunctionName{}; + string expectedOutput{}; + unsigned numFunctions = m_contractFunctionMap.size(); + unsigned contractIdx = randomNumber() % numFunctions; + unsigned functionIdx = 0; + unsigned mapIdx = 0; + for (auto &e: m_contractFunctionMap) + { + if (contractIdx == mapIdx) + { + chosenContractName = e.first; + functionIdx = random() % e.second.size(); + unsigned functionMapIdx = 0; + for (auto &f: e.second) + { + if (functionIdx == functionMapIdx) + { + chosenFunctionName = f.first; + expectedOutput = f.second; + break; + } + functionMapIdx++; + } + break; + } + mapIdx++; + } + solAssert(m_contractFunctionMap.count(chosenContractName), "Sol proto adaptor: Invalid contract chosen"); + solAssert(m_contractFunctionMap[chosenContractName].count(chosenFunctionName), "Sol proto adaptor: Invalid contract function chosen"); + return tuple(chosenContractName, chosenFunctionName, expectedOutput); +} + void SolContract::overrideHelper() { diff --git a/test/tools/ossfuzz/SolProtoAdaptor.h b/test/tools/ossfuzz/SolProtoAdaptor.h index 33340f341..8309ec563 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.h +++ b/test/tools/ossfuzz/SolProtoAdaptor.h @@ -251,7 +251,7 @@ struct SolContract void addBases(Contract const& _contract); void addOverrides(); void overrideHelper(); - bool validTest(); + bool validTest() const; std::tuple pseudoRandomTest(); unsigned randomNumber() const @@ -296,6 +296,9 @@ struct SolContract std::vector> m_contractFunctions; std::vector> m_baseContracts; std::vector> m_overriddenFunctions; + /// Maps non abstract contract name to list of publicly exposed function name + /// and their expected output + std::map> m_contractFunctionMap; std::shared_ptr m_prng; }; diff --git a/test/tools/ossfuzz/protoToSol.cpp b/test/tools/ossfuzz/protoToSol.cpp index 0f7f5296d..3c6114d80 100644 --- a/test/tools/ossfuzz/protoToSol.cpp +++ b/test/tools/ossfuzz/protoToSol.cpp @@ -629,7 +629,15 @@ string ProtoConverter::visit(Contract const& _contract) openProgramScope(&_contract); try { auto contract = SolContract(_contract, programName(&_contract), m_randomGen); - return contract.str(); + if (contract.validTest()) + { + m_contractTests.push_back(contract.pseudoRandomTest()); + return contract.str(); + } + // There is no point in generating a contract that can not provide + // a valid test case, so we simply bail. + else + return ""; } catch (langutil::FuzzerError const&) {