diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp index 8d5ced0a8..73462356b 100644 --- a/test/tools/ossfuzz/protoToYul.cpp +++ b/test/tools/ossfuzz/protoToYul.cpp @@ -178,6 +178,14 @@ bool ProtoConverter::functionCallNotPossible(FunctionCall_Returns _type) (_type == FunctionCall::MULTIASSIGN && !varDeclAvailable()); } +unsigned ProtoConverter::numVarsInScope() +{ + if (m_inFunctionDef) + return m_currentFuncVars.size(); + else + return m_currentGlobalVars.size(); +} + void ProtoConverter::visit(VarRef const& _x) { if (m_inFunctionDef) @@ -830,18 +838,18 @@ void ProtoConverter::visitFunctionInputParams(FunctionCall const& _x, unsigned _ case 4: visit(_x.in_param4()); m_output << ", "; - BOOST_FALLTHROUGH; + [[fallthrough]]; case 3: visit(_x.in_param3()); m_output << ", "; - BOOST_FALLTHROUGH; + [[fallthrough]]; case 2: visit(_x.in_param2()); m_output << ", "; - BOOST_FALLTHROUGH; + [[fallthrough]]; case 1: visit(_x.in_param1()); - BOOST_FALLTHROUGH; + [[fallthrough]]; case 0: break; default: @@ -966,23 +974,43 @@ void ProtoConverter::visit(FunctionCall const& _x) "Proto fuzzer: Function call with too many output params encountered." ); + // Return early if numOutParams > number of available variables + if (numOutParams > numVarsInScope()) + return; + + // Copy variables in scope in order to prevent repeated references + vector variables; + if (m_inFunctionDef) + for (auto var: m_currentFuncVars) + variables.push_back(*var); + else + for (auto var: m_currentGlobalVars) + variables.push_back(*var); + + auto refVar = [](vector& _var, unsigned _rand, bool _comma = true) -> string + { + auto index = _rand % _var.size(); + string ref = _var[index]; + _var.erase(_var.begin() + index); + if (_comma) + ref += ", "; + return ref; + }; + // Convert LHS of multi assignment // We reverse the order of out param visits since the order does not matter. // This helps reduce the size of this switch statement. switch (numOutParams) { case 4: - visit(_x.out_param4()); - m_output << ", "; - BOOST_FALLTHROUGH; + m_output << refVar(variables, _x.out_param4().varnum()); + [[fallthrough]]; case 3: - visit(_x.out_param3()); - m_output << ", "; - BOOST_FALLTHROUGH; + m_output << refVar(variables, _x.out_param3().varnum()); + [[fallthrough]]; case 2: - visit(_x.out_param2()); - m_output << ", "; - visit(_x.out_param1()); + m_output << refVar(variables, _x.out_param2().varnum()); + m_output << refVar(variables, _x.out_param1().varnum(), false); break; default: yulAssert(false, "Proto fuzzer: Function call with too many or too few input parameters."); diff --git a/test/tools/ossfuzz/protoToYul.h b/test/tools/ossfuzz/protoToYul.h index 9f7240f5e..950dd97a9 100644 --- a/test/tools/ossfuzz/protoToYul.h +++ b/test/tools/ossfuzz/protoToYul.h @@ -120,6 +120,8 @@ private: void closeFunctionScope(); /// Adds @a _vars to current scope void addVarsToScope(std::vector const& _vars); + /// @returns number of variables that are in scope + unsigned numVarsInScope(); std::string createHex(std::string const& _hexBytes);