diff --git a/test/tools/ossfuzz/SolProtoAdaptor.cpp b/test/tools/ossfuzz/SolProtoAdaptor.cpp index 549749ca5..407894ac8 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.cpp +++ b/test/tools/ossfuzz/SolProtoAdaptor.cpp @@ -186,12 +186,16 @@ SolContractFunction::SolContractFunction( bool SolContractFunction::operator==(SolContractFunction const& _rhs) const { - return this->m_visibility == _rhs.m_visibility && this->m_mutability == _rhs.m_mutability; + // TODO: Consider function parameters in addition to name once they are + // implemented. + return name() == _rhs.name(); } bool SolContractFunction::operator!=(SolContractFunction const& _rhs) const { - return this->m_visibility != _rhs.m_visibility || this->m_mutability != _rhs.m_mutability; + // TODO: Consider function parameters in addition to name once they are + // implemented. + return name() != _rhs.name(); } string SolContractFunction::str() const @@ -352,9 +356,6 @@ void SolInterface::addBases(Interface const& _interface) { auto base = make_shared(SolInterface(b, newBaseName(), m_prng)); m_baseInterfaces.push_back(base); -#if 0 - cout << "Added " << base->name() << " as base" << endl; -#endif // Worst case, we override all base functions so we // increment derived contract's function index by // this amount. @@ -378,9 +379,6 @@ void SolInterface::addFunctions(Interface const& _interface) SolInterface::SolInterface(Interface const& _interface, string _name, shared_ptr _prng) { -#if 0 - cout << "Constructing " << _name << endl; -#endif m_prng = _prng; m_interfaceName = _name; m_lastBaseName = m_interfaceName; @@ -430,8 +428,16 @@ string SolInterface::overrideStr() const sep = ", "; } } - else if (coinFlip()) - continue; + else + { + assertThrow( + f.second.size() == 1, + langutil::FuzzerError, + "Inconsistent override map" + ); + if (!f.second[0]->explicitlyInherited()) + continue; + } overriddenFunctions << Whiskers(R"( function () external override() returns (uint);)") ("functionName", f.first->name()) @@ -470,11 +476,18 @@ interface is { .render(); } -SolContract::SolContract(Contract const& _contract, std::string _name, shared_ptr _prng) +void SolContract::overrideHelper() +{ + +} + +void SolContract::addOverrides() +{ + +} + +void SolContract::addFunctions(Contract const& _contract) { - m_prng = _prng; - m_contractName = _name; - m_abstract = _contract.abstract(); for (auto &f: _contract.funcdef()) m_contractFunctions.push_back( make_unique( @@ -486,6 +499,10 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt ) ) ); +} + +void SolContract::addBases(Contract const& _contract) +{ for (auto &b: _contract.bases()) { switch (b.contract_or_interface_oneof_case()) @@ -493,14 +510,14 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt case ContractOrInterface::kC: m_baseContracts.push_back( make_unique( - SolBaseContract(&b.c(), newContractBaseName(), m_prng) + SolBaseContract(&b.c(), newBaseName(), m_prng) ) ); break; case ContractOrInterface::kI: m_baseContracts.push_back( make_unique( - SolBaseContract(&b.i(), newInterfaceBaseName(), m_prng) + SolBaseContract(&b.i(), newBaseName(), m_prng) ) ); break; @@ -510,6 +527,25 @@ SolContract::SolContract(Contract const& _contract, std::string _name, shared_pt } } +string SolContract::str() const +{ + return ""; +} + +SolContract::SolContract( + Contract const& _contract, + std::string _name, + shared_ptr _prng +) +{ + m_prng = _prng; + m_contractName = _name; + m_abstract = _contract.abstract(); + addBases(_contract); + addOverrides(); + addFunctions(_contract); +} + void SolLibrary::addFunction(LibraryFunction const& _function) { // Register function name and return value @@ -536,9 +572,10 @@ void SolLibrary::addFunction(LibraryFunction const& _function) ); } -SolLibrary::SolLibrary(Library const& _library, string _name) +SolLibrary::SolLibrary(Library const& _library, string _name, shared_ptr _prng) { m_libraryName = _name; + m_prng = _prng; for (LibraryFunction const& f: _library.funcdef()) addFunction(f); } @@ -564,17 +601,20 @@ bool SolLibrary::validTest() const return m_publicFunctionMap.size() > 0; } -pair SolLibrary::pseudoRandomTest(unsigned _randomIdx) +pair SolLibrary::pseudoRandomTest() { solAssert(m_publicFunctionMap.size() > 0, "Sol proto adaptor: Empty library map"); string chosenFunction; unsigned numFunctions = m_publicFunctionMap.size(); - unsigned functionIndex = _randomIdx % numFunctions; + unsigned functionIndex = randomNumber() % numFunctions; unsigned mapIdx = 0; for (auto &e: m_publicFunctionMap) { if (functionIndex == mapIdx) + { chosenFunction = e.first; + break; + } mapIdx++; } solAssert(m_publicFunctionMap.count(chosenFunction), "Sol proto adaptor: Invalid library function chosen"); diff --git a/test/tools/ossfuzz/SolProtoAdaptor.h b/test/tools/ossfuzz/SolProtoAdaptor.h index 44e6b567a..33340f341 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.h +++ b/test/tools/ossfuzz/SolProtoAdaptor.h @@ -194,7 +194,7 @@ struct SolLibraryFunction struct SolLibrary { - SolLibrary(Library const& _library, std::string _name); + SolLibrary(Library const& _library, std::string _name, std::shared_ptr _prng); std::vector> m_functions; /// Maps publicly exposed function name to expected output std::map m_publicFunctionMap; @@ -202,13 +202,15 @@ struct SolLibrary void addFunction(LibraryFunction const& _function); bool validTest() const; + unsigned randomNumber() const + { + return m_prng->operator()(); + } /// Returns a pair of function name and expected output /// that is pseudo randomly chosen from the list of all /// library functions. - /// @param _randomIdx A pseudo randomly generated number that is - /// used to index the list of all library functions. - std::pair pseudoRandomTest(unsigned _randomIdx); + std::pair pseudoRandomTest(); std::string str() const; @@ -228,6 +230,7 @@ struct SolLibrary std::string m_libraryName; unsigned m_functionIndex = 0; unsigned m_returnValue = 0; + std::shared_ptr m_prng; }; struct SolBaseContract @@ -244,8 +247,14 @@ struct SolContract SolContract(Contract const& _contract, std::string _name, std::shared_ptr _prng); std::string str() const; + void addFunctions(Contract const& _contract); + void addBases(Contract const& _contract); + void addOverrides(); + void overrideHelper(); + bool validTest(); + std::tuple pseudoRandomTest(); - unsigned randomNumber() + unsigned randomNumber() const { return m_prng->operator()(); } @@ -253,27 +262,27 @@ struct SolContract { return m_contractName; } - bool abstract() const { return m_abstract; } - std::string newFunctionName() { return "f" + std::to_string(m_functionIndex++); } - - std::string newContractBaseName() + unsigned functionIndex() const { - return name() + "B" + std::to_string(m_baseIndex++); + return m_functionIndex; } - - std::string newInterfaceBaseName() + std::string newBaseName() { - return "IB" + std::to_string(m_baseIndex++); + m_lastBaseName += "B"; + return m_lastBaseName; + } + std::string lastBaseName() const + { + return m_lastBaseName; } - std::string newReturnValue() { return std::to_string(m_returnValue++); @@ -281,12 +290,12 @@ struct SolContract std::string m_contractName; bool m_abstract = false; - unsigned m_baseIndex = 0; unsigned m_functionIndex = 0; unsigned m_returnValue = 0; - std::vector> m_contractFunctions; - std::vector> m_baseContracts; - std::vector> m_overriddenFunctions; + std::string m_lastBaseName; + std::vector> m_contractFunctions; + std::vector> m_baseContracts; + std::vector> m_overriddenFunctions; std::shared_ptr m_prng; }; @@ -375,6 +384,13 @@ struct SolInterface std::shared_ptr m_prng; }; +/* Contract functions may be overridden by other contracts. Base and derived contracts + * may either be abstract or non-abstract. That gives us four possibilities: + * - both abstract + * - both non abstract + * - one of them abstract, the other non abstract + */ + struct CFunctionOverride { CFunctionOverride( @@ -393,6 +409,12 @@ struct CFunctionOverride m_returnValue = _returnValue; } + enum class DerivedType + { + ABSTRACTCONTRACT, + CONTRACT + }; + enum class CFunctionOverrideType { INTERFACE, diff --git a/test/tools/ossfuzz/protoToSol.cpp b/test/tools/ossfuzz/protoToSol.cpp index dfc82df48..0f7f5296d 100644 --- a/test/tools/ossfuzz/protoToSol.cpp +++ b/test/tools/ossfuzz/protoToSol.cpp @@ -54,7 +54,7 @@ string ProtoConverter::visit(TestContract const& _testContract) else { m_libraryTest = true; - auto testTuple = pseudoRandomLibraryTest(_testContract.programidx()); + auto testTuple = pseudoRandomLibraryTest(); m_libraryName = get<0>(testTuple); usingLibDecl = Whiskers(R"( using for uint;)") @@ -72,20 +72,24 @@ string ProtoConverter::visit(TestContract const& _testContract) break; } case TestContract::CONTRACT: -#if 0 - testCode = Whiskers(R"( - testContract = new (); - if (testContract.() != ) - return 1; - return 0;)") - ("contractName", "") - ("testFunction", "") - ("expectedOutput", "") - .render(); -#else - testCode = Whiskers(R"( + if (emptyContractTests()) + testCode = Whiskers(R"( return 0;)") .render(); +#if 0 + else + { + auto testTuple = pseudoRandomContractTest(); + testCode = Whiskers(R"( + testContract = new (); + if (testContract.() != ) + return 1; + return 0;)") + ("contractName", get<0>(testTuple)) + ("testFunction", get<1>(testTuple)) + ("expectedOutput", get<2>(testTuple)) + .render(); + } #endif break; } @@ -615,25 +619,24 @@ tuple ProtoConverter::visitProgramHelper(CIL _program) } return make_tuple(bases.str(), baseNames.str(), funcs.str()); } +#endif string ProtoConverter::visit(Contract const& _contract) { + if (_contract.funcdef_size() == 0 && _contract.bases_size() == 0) + return ""; + openProgramScope(&_contract); - auto [bases, baseNames, funcs] = visitProgramHelper(&_contract); - return Whiskers(R"( - -abstract contract is { - -})") - ("bases", bases) - ("isAbstract", _contract.abstract()) - ("programName", programName(&_contract)) - ("inheritance", _contract.bases_size() > 0 && !baseNames.empty()) - ("baseNames", baseNames) - ("functionDefs", funcs) - .render(); + try { + auto contract = SolContract(_contract, programName(&_contract), m_randomGen); + return contract.str(); + } + catch (langutil::FuzzerError const&) + { + // Return empty string if input specification is invalid. + return ""; + } } -#endif string ProtoConverter::visit(Interface const& _interface) { @@ -658,22 +661,29 @@ string ProtoConverter::visit(Library const& _library) return ""; openProgramScope(&_library); - auto lib = SolLibrary(_library, programName(&_library)); + auto lib = SolLibrary(_library, programName(&_library), m_randomGen); if (lib.validTest()) { - auto libTestPair = lib.pseudoRandomTest(_library.random()); + auto libTestPair = lib.pseudoRandomTest(); m_libraryTests.push_back({lib.name(), libTestPair.first, libTestPair.second}); } return lib.str(); } -tuple ProtoConverter::pseudoRandomLibraryTest(unsigned _randomIdx) +tuple ProtoConverter::pseudoRandomLibraryTest() { solAssert(m_libraryTests.size() > 0, "Sol proto fuzzer: No library tests found"); - unsigned index = _randomIdx % m_libraryTests.size(); + unsigned index = randomNumber() % m_libraryTests.size(); return m_libraryTests[index]; } +tuple ProtoConverter::pseudoRandomContractTest() +{ + solAssert(m_contractTests.size() > 0, "Sol proto fuzzer: No contract tests found"); + unsigned index = randomNumber() % m_contractTests.size(); + return m_contractTests[index]; +} + void ProtoConverter::openProgramScope(CIL _program) { string programNamePrefix; diff --git a/test/tools/ossfuzz/protoToSol.h b/test/tools/ossfuzz/protoToSol.h index 7081dc8ef..ffd3049e3 100644 --- a/test/tools/ossfuzz/protoToSol.h +++ b/test/tools/ossfuzz/protoToSol.h @@ -121,7 +121,8 @@ private: Contract const* _derived, CIFunc _baseFunc ); - std::tuple pseudoRandomLibraryTest(unsigned _randomIdx); + std::tuple pseudoRandomLibraryTest(); + std::tuple pseudoRandomContractTest(); bool emptyLibrary(Library const& _library) { @@ -131,6 +132,10 @@ private: { return m_libraryTests.size() == 0; } + bool emptyContractTests() + { + return m_contractTests.size() == 0; + } void openProgramScope(CIL _program); bool pseudoRandomCoinFlip() @@ -155,7 +160,6 @@ private: static bool disallowedContractFunction(SolContractFunction const& _contractFunction, bool _isVirtual); #endif - unsigned m_numMods = 0; unsigned m_numPrograms = 0; unsigned m_counter = 0; bool m_mostDerivedAbstractContract = false; @@ -194,6 +198,7 @@ private: std::map>> m_programFunctionNameMap; std::vector> m_libraryTests; + std::vector> m_contractTests; std::string m_libraryName; static auto constexpr s_interfaceFunctionPrefix = "i"; diff --git a/test/tools/ossfuzz/solProto.proto b/test/tools/ossfuzz/solProto.proto index c73f9b73d..0ea15bb85 100644 --- a/test/tools/ossfuzz/solProto.proto +++ b/test/tools/ossfuzz/solProto.proto @@ -61,7 +61,6 @@ message ContractFunction { message Library { repeated LibraryFunction funcdef = 1; - required uint64 random = 2; } message Interface { @@ -96,7 +95,6 @@ message TestContract { CONTRACT = 1; } required Type type = 1; - required uint64 programidx = 2; } message Program {