From b2c624bf9ca4092ccecb6c88d45c6e422562403f Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Thu, 16 Apr 2020 13:28:17 +0200 Subject: [PATCH] Expose base functions for testing even if they hide beneath abstract contract --- test/tools/ossfuzz/SolProtoAdaptor.cpp | 71 ++++++++++++++++++-------- test/tools/ossfuzz/SolProtoAdaptor.h | 2 +- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/test/tools/ossfuzz/SolProtoAdaptor.cpp b/test/tools/ossfuzz/SolProtoAdaptor.cpp index 61fa8e432..9d7ae4967 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.cpp +++ b/test/tools/ossfuzz/SolProtoAdaptor.cpp @@ -700,34 +700,65 @@ string SolContract::baseNames() const bool SolContract::validTest() { - return m_contractFunctionMap[name()].size() > 0; + // If we have at least one function-expectation pair in this contract + // we have a valid test + if (!m_contractFunctionMap.empty()) + return true; + else + { + // If this contract does not offer a valid test, we check if its + // base contracts offer one. + for (auto &b: m_baseContracts) + { + if (b->type() == SolBaseContract::BaseType::CONTRACT) + { + if (b->contract()->validTest()) + return true; + } + } + return false; + } } +/// Must be called only when validTest() returns true. tuple SolContract::validContractTest() { - string chosenContractName = name(); + string chosenContractName; string chosenFunctionName{}; string expectedOutput{}; - unsigned functionIdx = random() % m_contractFunctionMap[name()].size(); - unsigned mapIdx = 0; - for (auto &e: m_contractFunctionMap[name()]) + // If we can provide a test case right away, do so. + if (!m_contractFunctionMap.empty()) { - if (functionIdx == mapIdx) + chosenContractName = name(); + unsigned functionIdx = random() % m_contractFunctionMap.size(); + unsigned mapIdx = 0; + for (auto &e: m_contractFunctionMap) { - chosenFunctionName = e.first; - expectedOutput = e.second; - break; + if (functionIdx == mapIdx) + { + chosenFunctionName = e.first; + expectedOutput = e.second; + break; + } + mapIdx++; } - mapIdx++; + solAssert(m_contractFunctionMap.count(chosenFunctionName), "Sol proto adaptor: Invalid contract function chosen"); + return make_tuple(chosenContractName, chosenFunctionName, expectedOutput); } - 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); + // Otherwise, continue search in base contracts + else + { + for (auto &b: m_baseContracts) + if (b->type() == SolBaseContract::BaseType::CONTRACT) + if (b->contract()->validTest()) + return b->contract()->validContractTest(); + } + solAssert(false, "Sol proto adaptor: No contract test found"); } tuple SolContract::pseudoRandomTest() { - solAssert(validTest(), "Sol proto adaptor: No valid contract test cases"); + solAssert(validTest(), "Sol proto adaptor: Please call validTest()"); return validContractTest(); } @@ -760,8 +791,8 @@ void SolContract::addFunctions(Contract const& _contract) // be called from a different contract. if (visibility == SolFunctionVisibility::PUBLIC || visibility == SolFunctionVisibility::EXTERNAL) { - solAssert(!m_contractFunctionMap[contractName].count(functionName), "Sol proto adaptor: Duplicate contract function"); - m_contractFunctionMap[contractName].insert(pair(functionName, expectedOutput)); + solAssert(!m_contractFunctionMap.count(functionName), "Sol proto adaptor: Duplicate contract function"); + m_contractFunctionMap.insert(pair(functionName, expectedOutput)); } } } @@ -1208,7 +1239,7 @@ void SolContract::merge() { auto function = get>(f); if (function->implemented() && (function->visibility() == SolFunctionVisibility::EXTERNAL || function->visibility() == SolFunctionVisibility::PUBLIC)) - m_contractFunctionMap[name()].insert(pair(function->name(), function->returnValue())); + m_contractFunctionMap.insert(pair(function->name(), function->returnValue())); } } @@ -1279,10 +1310,8 @@ SolContract::SolContract( m_contractName = _name; m_lastBaseName = m_contractName; m_abstract = _contract.abstract(); - // Add contract to contract function map only if the contract - // is not abstract. - if (!m_abstract) - m_contractFunctionMap.insert(pair(m_contractName, map{})); + // Initialize function map. + m_contractFunctionMap = map{}; addBases(_contract); addFunctions(_contract); } diff --git a/test/tools/ossfuzz/SolProtoAdaptor.h b/test/tools/ossfuzz/SolProtoAdaptor.h index eba400fac..1817d6a2d 100644 --- a/test/tools/ossfuzz/SolProtoAdaptor.h +++ b/test/tools/ossfuzz/SolProtoAdaptor.h @@ -541,7 +541,7 @@ struct SolContract std::vector> m_baseContracts; /// Maps non abstract contract name to list of publicly exposed function name /// and their expected output - std::map> m_contractFunctionMap; + std::map m_contractFunctionMap; std::shared_ptr m_prng; };