diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp index cc7fde3ae..f5f67fc02 100644 --- a/test/tools/ossfuzz/protoToYul.cpp +++ b/test/tools/ossfuzz/protoToYul.cpp @@ -35,9 +35,18 @@ using namespace solidity; string ProtoConverter::dictionaryToken(HexPrefix _p) { - unsigned indexVar = m_inputSize * m_inputSize + counter(); - std::string token = hexDictionary[indexVar % hexDictionary.size()]; - yulAssert(token.size() <= 64, "Proto Fuzzer: Dictionary token too large"); + std::string token; + // If dictionary constant is requested while converting + // for loop condition, then return zero so that we don't + // generate infinite for loops. + if (m_inForCond) + token = "0"; + else + { + unsigned indexVar = m_inputSize * m_inputSize + counter(); + token = hexDictionary[indexVar % hexDictionary.size()]; + yulAssert(token.size() <= 64, "Proto Fuzzer: Dictionary token too large"); + } return _p == HexPrefix::Add ? "0x" + token : token; } @@ -173,7 +182,13 @@ void ProtoConverter::visit(Expression const& _x) visit(_x.varref()); break; case Expression::kCons: - m_output << visit(_x.cons()); + // If literal expression describes for-loop condition + // then force it to zero, so we don't generate infinite + // for loops + if (m_inForCond) + m_output << "0"; + else + m_output << visit(_x.cons()); break; case Expression::kBinop: visit(_x.binop()); @@ -964,17 +979,22 @@ void ProtoConverter::visit(StoreFunc const& _x) void ProtoConverter::visit(ForStmt const& _x) { + if (++m_numForLoops > s_maxForLoops) + return; bool wasInForBody = m_inForBodyScope; bool wasInForInit = m_inForInitScope; bool wasForInitScopeExtEnabled = m_forInitScopeExtEnabled; m_inForBodyScope = false; m_inForInitScope = true; m_forInitScopeExtEnabled = true; + m_inForCond = false; m_output << "for "; visit(_x.for_init()); m_inForInitScope = false; m_forInitScopeExtEnabled = wasForInitScopeExtEnabled; + m_inForCond = true; visit(_x.for_cond()); + m_inForCond = false; visit(_x.for_post()); m_inForBodyScope = true; visit(_x.for_body()); @@ -997,6 +1017,9 @@ void ProtoConverter::visit(ForStmt const& _x) void ProtoConverter::visit(BoundedForStmt const& _x) { + if (++m_numForLoops > s_maxForLoops) + return; + // Boilerplate for loop that limits the number of iterations to a maximum of 4. std::string loopVarName("i_" + std::to_string(m_numNestedForLoops++)); m_output << "for { let " << loopVarName << " := 0 } " diff --git a/test/tools/ossfuzz/protoToYul.h b/test/tools/ossfuzz/protoToYul.h index 4150e7c64..37321c78c 100644 --- a/test/tools/ossfuzz/protoToYul.h +++ b/test/tools/ossfuzz/protoToYul.h @@ -42,7 +42,9 @@ public: m_globalVars = std::vector>{}; m_inForBodyScope = false; m_inForInitScope = false; + m_inForCond = false; m_numNestedForLoops = 0; + m_numForLoops = 0; m_counter = 0; m_inputSize = 0; m_inFunctionDef = false; @@ -339,11 +341,18 @@ private: /// Predicate to keep track of for body scope. If false, break/continue /// statements can not be created. bool m_inForBodyScope; + /// Maximum number of for loops that a test case may contain + static auto constexpr s_maxForLoops = 2; // Index used for naming loop variable of bounded for loops unsigned m_numNestedForLoops; + /// Counter for number of for loops + unsigned m_numForLoops; /// Predicate to keep track of for loop init scope. If true, variable /// or function declarations can not be created. bool m_inForInitScope; + /// Flag that is true while converting for loop condition, + /// false otherwise. + bool m_inForCond; /// Monotonically increasing counter unsigned m_counter; /// Size of protobuf input