From b5cbb1a3e9c1564b30e0862af5db251a7c614113 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Tue, 26 Mar 2019 10:52:30 +0100 Subject: [PATCH] For loop with custom init and post blocks and potentially unbounded conditional expression --- test/tools/ossfuzz/protoToYul.cpp | 48 ++++++++++++++++++++++++------- test/tools/ossfuzz/protoToYul.h | 15 ++++++---- test/tools/ossfuzz/yulProto.proto | 8 ++++++ 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp index 6582d6b4e..f32fda260 100644 --- a/test/tools/ossfuzz/protoToYul.cpp +++ b/test/tools/ossfuzz/protoToYul.cpp @@ -616,7 +616,9 @@ void ProtoConverter::visit(FunctionCall const& _x) visit(_x.call_zero()); break; case FunctionCall::kCallMultidecl: - visit(_x.call_multidecl()); + // Hack: Disallow (multi) variable declarations until scope extension is implemented for "for-init" + if (!m_inForInitScope) + visit(_x.call_multidecl()); break; case FunctionCall::kCallMultiassign: visit(_x.call_multiassign()); @@ -655,17 +657,38 @@ void ProtoConverter::visit(StoreFunc const& _x) } void ProtoConverter::visit(ForStmt const& _x) +{ + bool wasInForBody = m_inForBodyScope; + bool wasInForInit = m_inForInitScope; + m_inForBodyScope = false; + m_inForInitScope = true; + m_output << "for "; + visit(_x.for_init()); + m_inForInitScope = false; + visit(_x.for_cond()); + visit(_x.for_post()); + m_inForBodyScope = true; + visit(_x.for_body()); + m_inForBodyScope = wasInForBody; + m_inForInitScope = wasInForInit; +} + +void ProtoConverter::visit(BoundedForStmt const& _x) { // Boilerplate for loop that limits the number of iterations to a maximum of 4. - // TODO: Generalize for loop init, condition, and post blocks. std::string loopVarName("i_" + std::to_string(m_numNestedForLoops++)); m_output << "for { let " << loopVarName << " := 0 } " - << "lt(" << loopVarName << ", 0x60) " - << "{ " << loopVarName << " := add(" << loopVarName << ", 0x20) } "; - m_inForScope.push(true); + << "lt(" << loopVarName << ", 0x60) " + << "{ " << loopVarName << " := add(" << loopVarName << ", 0x20) } "; + // Store previous for body scope + bool wasInForBody = m_inForBodyScope; + bool wasInForInit = m_inForInitScope; + m_inForBodyScope = true; + m_inForInitScope = false; visit(_x.for_body()); - m_inForScope.pop(); - --m_numNestedForLoops; + // Restore previous for body scope and init + m_inForBodyScope = wasInForBody; + m_inForInitScope = wasInForInit; } void ProtoConverter::visit(CaseStmt const& _x) @@ -765,7 +788,9 @@ void ProtoConverter::visit(Statement const& _x) switch (_x.stmt_oneof_case()) { case Statement::kDecl: - visit(_x.decl()); + // Hack: Disallow (multi) variable declarations until scope extension is implemented for "for-init" + if (!m_inForInitScope) + visit(_x.decl()); break; case Statement::kAssignment: visit(_x.assignment()); @@ -782,15 +807,18 @@ void ProtoConverter::visit(Statement const& _x) case Statement::kForstmt: visit(_x.forstmt()); break; + case Statement::kBoundedforstmt: + visit(_x.boundedforstmt()); + break; case Statement::kSwitchstmt: visit(_x.switchstmt()); break; case Statement::kBreakstmt: - if (m_inForScope.top()) + if (m_inForBodyScope) m_output << "break\n"; break; case Statement::kContstmt: - if (m_inForScope.top()) + if (m_inForBodyScope) m_output << "continue\n"; break; case Statement::kLogFunc: diff --git a/test/tools/ossfuzz/protoToYul.h b/test/tools/ossfuzz/protoToYul.h index dc707a0fa..bea31b1e5 100644 --- a/test/tools/ossfuzz/protoToYul.h +++ b/test/tools/ossfuzz/protoToYul.h @@ -42,9 +42,10 @@ public: { m_numLiveVars = 0; m_numVarsPerScope.push(m_numLiveVars); - m_numNestedForLoops = 0; - m_inForScope.push(false); m_numFunctionSets = 0; + m_inForBodyScope = false; + m_inForInitScope = false; + m_numNestedForLoops = 0; } ProtoConverter(ProtoConverter const&) = delete; ProtoConverter(ProtoConverter&&) = delete; @@ -69,6 +70,7 @@ private: void visit(Statement const&); void visit(FunctionDefinition const&); void visit(ForStmt const&); + void visit(BoundedForStmt const&); void visit(CaseStmt const&); void visit(SwitchStmt const&); void visit(TernaryOp const&); @@ -131,9 +133,6 @@ private: std::stack m_numVarsPerScope; // Number of live variables in function scope unsigned m_numLiveVars; - // Number of nested for loops for loop index referencing - unsigned m_numNestedForLoops; - std::stack m_inForScope; // Set that is used for deduplicating switch case literals std::stack> m_switchLiteralSetPerScope; // Total number of function sets. A function set contains one function of each type defined by @@ -146,6 +145,12 @@ private: // mod input/output parameters impose an upper bound on the number of input/output parameters a function may have. static unsigned constexpr modInputParams = 5; static unsigned constexpr modOutputParams = 5; + // predicate to keep track of for body scope + bool m_inForBodyScope; + // Index used for naming loop variable of bounded for loops + unsigned m_numNestedForLoops; + // predicate to keep track of for loop init scope + bool m_inForInitScope; }; } } diff --git a/test/tools/ossfuzz/yulProto.proto b/test/tools/ossfuzz/yulProto.proto index 4793a029f..4a39ab258 100644 --- a/test/tools/ossfuzz/yulProto.proto +++ b/test/tools/ossfuzz/yulProto.proto @@ -256,8 +256,15 @@ message IfStmt { required Block if_body = 2; } +message BoundedForStmt { + required Block for_body = 1; +} + message ForStmt { required Block for_body = 1; + required Block for_init = 2; + required Block for_post = 3; + required Expression for_cond = 4; } message CaseStmt { @@ -324,6 +331,7 @@ message Statement { ExtCodeCopy extcode_copy = 12; TerminatingStmt terminatestmt = 13; FunctionCall functioncall = 14; + BoundedForStmt boundedforstmt = 15; } }