Merge pull request #8172 from ethereum/fix-7803

yul proto fuzzer: Do not generate infinite for loops and limit number of for loops
This commit is contained in:
chriseth 2020-01-20 12:32:04 +01:00 committed by GitHub
commit 18bf3688be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 4 deletions

View File

@ -35,9 +35,18 @@ using namespace solidity;
string ProtoConverter::dictionaryToken(HexPrefix _p) string ProtoConverter::dictionaryToken(HexPrefix _p)
{ {
unsigned indexVar = m_inputSize * m_inputSize + counter(); std::string token;
std::string token = hexDictionary[indexVar % hexDictionary.size()]; // If dictionary constant is requested while converting
yulAssert(token.size() <= 64, "Proto Fuzzer: Dictionary token too large"); // 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; return _p == HexPrefix::Add ? "0x" + token : token;
} }
@ -173,7 +182,13 @@ void ProtoConverter::visit(Expression const& _x)
visit(_x.varref()); visit(_x.varref());
break; break;
case Expression::kCons: 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; break;
case Expression::kBinop: case Expression::kBinop:
visit(_x.binop()); visit(_x.binop());
@ -964,17 +979,22 @@ void ProtoConverter::visit(StoreFunc const& _x)
void ProtoConverter::visit(ForStmt const& _x) void ProtoConverter::visit(ForStmt const& _x)
{ {
if (++m_numForLoops > s_maxForLoops)
return;
bool wasInForBody = m_inForBodyScope; bool wasInForBody = m_inForBodyScope;
bool wasInForInit = m_inForInitScope; bool wasInForInit = m_inForInitScope;
bool wasForInitScopeExtEnabled = m_forInitScopeExtEnabled; bool wasForInitScopeExtEnabled = m_forInitScopeExtEnabled;
m_inForBodyScope = false; m_inForBodyScope = false;
m_inForInitScope = true; m_inForInitScope = true;
m_forInitScopeExtEnabled = true; m_forInitScopeExtEnabled = true;
m_inForCond = false;
m_output << "for "; m_output << "for ";
visit(_x.for_init()); visit(_x.for_init());
m_inForInitScope = false; m_inForInitScope = false;
m_forInitScopeExtEnabled = wasForInitScopeExtEnabled; m_forInitScopeExtEnabled = wasForInitScopeExtEnabled;
m_inForCond = true;
visit(_x.for_cond()); visit(_x.for_cond());
m_inForCond = false;
visit(_x.for_post()); visit(_x.for_post());
m_inForBodyScope = true; m_inForBodyScope = true;
visit(_x.for_body()); visit(_x.for_body());
@ -997,6 +1017,9 @@ void ProtoConverter::visit(ForStmt const& _x)
void ProtoConverter::visit(BoundedForStmt 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. // Boilerplate for loop that limits the number of iterations to a maximum of 4.
std::string loopVarName("i_" + std::to_string(m_numNestedForLoops++)); std::string loopVarName("i_" + std::to_string(m_numNestedForLoops++));
m_output << "for { let " << loopVarName << " := 0 } " m_output << "for { let " << loopVarName << " := 0 } "

View File

@ -42,7 +42,9 @@ public:
m_globalVars = std::vector<std::vector<std::string>>{}; m_globalVars = std::vector<std::vector<std::string>>{};
m_inForBodyScope = false; m_inForBodyScope = false;
m_inForInitScope = false; m_inForInitScope = false;
m_inForCond = false;
m_numNestedForLoops = 0; m_numNestedForLoops = 0;
m_numForLoops = 0;
m_counter = 0; m_counter = 0;
m_inputSize = 0; m_inputSize = 0;
m_inFunctionDef = false; m_inFunctionDef = false;
@ -339,11 +341,18 @@ private:
/// Predicate to keep track of for body scope. If false, break/continue /// Predicate to keep track of for body scope. If false, break/continue
/// statements can not be created. /// statements can not be created.
bool m_inForBodyScope; 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 // Index used for naming loop variable of bounded for loops
unsigned m_numNestedForLoops; unsigned m_numNestedForLoops;
/// Counter for number of for loops
unsigned m_numForLoops;
/// Predicate to keep track of for loop init scope. If true, variable /// Predicate to keep track of for loop init scope. If true, variable
/// or function declarations can not be created. /// or function declarations can not be created.
bool m_inForInitScope; bool m_inForInitScope;
/// Flag that is true while converting for loop condition,
/// false otherwise.
bool m_inForCond;
/// Monotonically increasing counter /// Monotonically increasing counter
unsigned m_counter; unsigned m_counter;
/// Size of protobuf input /// Size of protobuf input