Merge pull request #9960 from ethereum/stackLimitEvaderRefactor

StackLimitEvader: Track unreachable variables globally instead of per function.
This commit is contained in:
chriseth 2020-10-08 19:01:26 +02:00 committed by GitHub
commit 70ebc0a13c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 37 deletions

View File

@ -66,14 +66,13 @@ struct MemoryOffsetAllocator
if (unreachableVariables.count(_function)) if (unreachableVariables.count(_function))
{ {
yulAssert(!slotAllocations.count(_function), ""); yulAssert(!slotAllocations.count(_function), "");
auto& assignedSlots = slotAllocations[_function];
for (YulString variable: unreachableVariables.at(_function)) for (YulString variable: unreachableVariables.at(_function))
if (variable.empty()) if (variable.empty())
{ {
// TODO: Too many function arguments or return parameters. // TODO: Too many function arguments or return parameters.
} }
else else
assignedSlots[variable] = requiredSlots++; slotAllocations[variable] = requiredSlots++;
} }
return slotsRequiredForFunction[_function] = requiredSlots; return slotsRequiredForFunction[_function] = requiredSlots;
@ -82,7 +81,7 @@ struct MemoryOffsetAllocator
map<YulString, set<YulString>> const& unreachableVariables; map<YulString, set<YulString>> const& unreachableVariables;
map<YulString, set<YulString>> const& callGraph; map<YulString, set<YulString>> const& callGraph;
map<YulString, map<YulString, uint64_t>> slotAllocations{}; map<YulString, uint64_t> slotAllocations{};
map<YulString, uint64_t> slotsRequiredForFunction{}; map<YulString, uint64_t> slotsRequiredForFunction{};
}; };

View File

@ -54,7 +54,7 @@ vector<Statement> generateMemoryStore(
void StackToMemoryMover::run( void StackToMemoryMover::run(
OptimiserStepContext& _context, OptimiserStepContext& _context,
u256 _reservedMemory, u256 _reservedMemory,
map<YulString, map<YulString, uint64_t>> const& _memorySlots, map<YulString, uint64_t> const& _memorySlots,
uint64_t _numRequiredSlots, uint64_t _numRequiredSlots,
Block& _block Block& _block
) )
@ -66,7 +66,7 @@ void StackToMemoryMover::run(
StackToMemoryMover::StackToMemoryMover( StackToMemoryMover::StackToMemoryMover(
OptimiserStepContext& _context, OptimiserStepContext& _context,
u256 _reservedMemory, u256 _reservedMemory,
map<YulString, map<YulString, uint64_t>> const& _memorySlots, map<YulString, uint64_t> const& _memorySlots,
uint64_t _numRequiredSlots uint64_t _numRequiredSlots
): ):
m_context(_context), m_context(_context),
@ -80,41 +80,25 @@ m_nameDispenser(_context.dispenser)
evmDialect && evmDialect->providesObjectAccess(), evmDialect && evmDialect->providesObjectAccess(),
"StackToMemoryMover can only be run on objects using the EVMDialect with object access." "StackToMemoryMover can only be run on objects using the EVMDialect with object access."
); );
if (m_memorySlots.count(YulString{}))
// If the global scope contains variables to be moved, start with those as if it were a function.
m_currentFunctionMemorySlots = &m_memorySlots.at(YulString{});
} }
void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition) void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
{ {
if (m_memorySlots.count(_functionDefinition.name)) for (TypedName const& param: _functionDefinition.parameters + _functionDefinition.returnVariables)
{ if (m_memorySlots.count(param.name))
map<YulString, uint64_t> const* saved = m_currentFunctionMemorySlots; {
m_currentFunctionMemorySlots = &m_memorySlots.at(_functionDefinition.name); // TODO: we cannot handle function parameters yet.
for (TypedName const& param: _functionDefinition.parameters + _functionDefinition.returnVariables) return;
if (m_currentFunctionMemorySlots->count(param.name)) }
{ ASTModifier::operator()(_functionDefinition);
// TODO: we cannot handle function parameters yet.
m_currentFunctionMemorySlots = saved;
return;
}
ASTModifier::operator()(_functionDefinition);
m_currentFunctionMemorySlots = saved;
}
} }
void StackToMemoryMover::operator()(Block& _block) void StackToMemoryMover::operator()(Block& _block)
{ {
using OptionalStatements = std::optional<vector<Statement>>; using OptionalStatements = std::optional<vector<Statement>>;
if (!m_currentFunctionMemorySlots)
{
ASTModifier::operator()(_block);
return;
}
auto containsVariableNeedingEscalation = [&](auto const& _variables) { auto containsVariableNeedingEscalation = [&](auto const& _variables) {
return util::contains_if(_variables, [&](auto const& var) { return util::contains_if(_variables, [&](auto const& var) {
return m_currentFunctionMemorySlots->count(var.name); return m_memorySlots.count(var.name);
}); });
}; };
auto rewriteAssignmentOrVariableDeclaration = [&]( auto rewriteAssignmentOrVariableDeclaration = [&](
@ -138,7 +122,7 @@ void StackToMemoryMover::operator()(Block& _block)
YulString tempVarName = m_nameDispenser.newName(var.name); YulString tempVarName = m_nameDispenser.newName(var.name);
tempDecl.variables.emplace_back(TypedName{var.location, tempVarName, {}}); tempDecl.variables.emplace_back(TypedName{var.location, tempVarName, {}});
if (m_currentFunctionMemorySlots->count(var.name)) if (m_memorySlots.count(var.name))
memoryAssignments += generateMemoryStore( memoryAssignments += generateMemoryStore(
m_context.dialect, m_context.dialect,
_loc, _loc,
@ -203,7 +187,7 @@ void StackToMemoryMover::visit(Expression& _expression)
{ {
if ( if (
Identifier* identifier = std::get_if<Identifier>(&_expression); Identifier* identifier = std::get_if<Identifier>(&_expression);
identifier && m_currentFunctionMemorySlots && m_currentFunctionMemorySlots->count(identifier->name) identifier && m_memorySlots.count(identifier->name)
) )
{ {
BuiltinFunction const* memoryLoadFunction = m_context.dialect.memoryLoadFunction(m_context.dialect.defaultType); BuiltinFunction const* memoryLoadFunction = m_context.dialect.memoryLoadFunction(m_context.dialect.defaultType);
@ -227,8 +211,8 @@ void StackToMemoryMover::visit(Expression& _expression)
YulString StackToMemoryMover::memoryOffset(YulString _variable) YulString StackToMemoryMover::memoryOffset(YulString _variable)
{ {
yulAssert(m_currentFunctionMemorySlots, ""); yulAssert(m_memorySlots.count(_variable), "");
uint64_t slot = m_currentFunctionMemorySlots->at(_variable); uint64_t slot = m_memorySlots.at(_variable);
yulAssert(slot < m_numRequiredSlots, ""); yulAssert(slot < m_numRequiredSlots, "");
return YulString{util::toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))}; return YulString{util::toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))};
} }

View File

@ -90,7 +90,7 @@ public:
static void run( static void run(
OptimiserStepContext& _context, OptimiserStepContext& _context,
u256 _reservedMemory, u256 _reservedMemory,
std::map<YulString, std::map<YulString, uint64_t>> const& _memorySlots, std::map<YulString, uint64_t> const& _memorySlots,
uint64_t _numRequiredSlots, uint64_t _numRequiredSlots,
Block& _block Block& _block
); );
@ -103,7 +103,7 @@ private:
StackToMemoryMover( StackToMemoryMover(
OptimiserStepContext& _context, OptimiserStepContext& _context,
u256 _reservedMemory, u256 _reservedMemory,
std::map<YulString, std::map<YulString, uint64_t>> const& _memorySlots, std::map<YulString, uint64_t> const& _memorySlots,
uint64_t _numRequiredSlots uint64_t _numRequiredSlots
); );
@ -112,10 +112,9 @@ private:
OptimiserStepContext& m_context; OptimiserStepContext& m_context;
u256 m_reservedMemory; u256 m_reservedMemory;
std::map<YulString, std::map<YulString, uint64_t>> const& m_memorySlots; std::map<YulString, uint64_t> const& m_memorySlots;
uint64_t m_numRequiredSlots = 0; uint64_t m_numRequiredSlots = 0;
NameDispenser& m_nameDispenser; NameDispenser& m_nameDispenser;
std::map<YulString, uint64_t> const* m_currentFunctionMemorySlots = nullptr;
}; };
} }