Report all stack errors in the EVM code transform.

This commit is contained in:
Daniel Kirchner 2020-07-08 12:54:52 +02:00 committed by chriseth
parent f9753a5101
commit 579e4b5a69
5 changed files with 27 additions and 48 deletions

View File

@ -59,14 +59,7 @@ map<YulString, int> CompilabilityChecker::run(
builtinContext, builtinContext,
_optimizeStackAllocation _optimizeStackAllocation
); );
try transform(*_object.code);
{
transform(*_object.code);
}
catch (StackTooDeepError const&)
{
yulAssert(!transform.stackErrors().empty(), "Got stack too deep exception that was not stored.");
}
std::map<YulString, int> functions; std::map<YulString, int> functions;
for (StackTooDeepError const& error: transform.stackErrors()) for (StackTooDeepError const& error: transform.stackErrors())

View File

@ -231,18 +231,12 @@ void CodeGenerator::assemble(
_identifierAccess, _identifierAccess,
_useNamedLabelsForFunctions _useNamedLabelsForFunctions
); );
try transform(_parsedData);
{ if (!transform.stackErrors().empty())
transform(_parsedData);
}
catch (StackTooDeepError const& _e)
{
assertThrow( assertThrow(
false, false,
langutil::StackTooDeepError, langutil::StackTooDeepError,
"Stack too deep when compiling inline assembly" + "Stack too deep when compiling inline assembly" +
(_e.comment() ? ": " + *_e.comment() : ".") (transform.stackErrors().front().comment() ? ": " + *transform.stackErrors().front().comment() : ".")
); );
}
yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown.");
} }

View File

@ -435,31 +435,24 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_context->functionExitPoints.push( m_context->functionExitPoints.push(
CodeTransformContext::JumpInfo{m_assembly.newLabelId(), m_assembly.stackHeight()} CodeTransformContext::JumpInfo{m_assembly.newLabelId(), m_assembly.stackHeight()}
); );
try CodeTransform subTransform(
m_assembly,
m_info,
_function.body,
m_allowStackOpt,
m_dialect,
m_builtinContext,
m_evm15,
m_identifierAccess,
m_useNamedLabelsForFunctions,
m_context
);
subTransform(_function.body);
for (auto& stackError: subTransform.m_stackErrors)
{ {
CodeTransform( if (stackError.functionName.empty())
m_assembly, stackError.functionName = _function.name;
m_info, m_stackErrors.emplace_back(std::move(stackError));
_function.body,
m_allowStackOpt,
m_dialect,
m_builtinContext,
m_evm15,
m_identifierAccess,
m_useNamedLabelsForFunctions,
m_context
)(_function.body);
}
catch (StackTooDeepError const& _error)
{
// This exception will be re-thrown after the end of the surrounding block.
// It enables us to see which functions compiled successfully and which did not.
// Even if we emit actual code, add an illegal instruction to make sure that tests
// will catch it.
StackTooDeepError error(_error);
if (error.functionName.empty())
error.functionName = _function.name;
stackError(std::move(error), static_cast<int>(height));
} }
m_assembly.appendLabel(m_context->functionExitPoints.top().label); m_assembly.appendLabel(m_context->functionExitPoints.top().label);
@ -605,9 +598,6 @@ void CodeTransform::operator()(Block const& _block)
finalizeBlock(_block, blockStartStackHeight); finalizeBlock(_block, blockStartStackHeight);
m_scope = originalScope; m_scope = originalScope;
if (!m_stackErrors.empty())
BOOST_THROW_EXCEPTION(m_stackErrors.front());
} }
AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function) AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function)
@ -728,7 +718,8 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString
to_string(heightDiff - limit) + to_string(heightDiff - limit) +
" slot(s) too deep inside the stack." " slot(s) too deep inside the stack."
); );
BOOST_THROW_EXCEPTION(m_stackErrors.back()); // TODO: maybe make this return something special that results in producing INVALID instead.
return _forSwap ? 2 : 1;
} }
return heightDiff; return heightDiff;
} }

View File

@ -59,5 +59,6 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
// which should be native to this part of the code. // which should be native to this part of the code.
CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize, m_evm15}; CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize, m_evm15};
transform(*_object.code); transform(*_object.code);
yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown."); if (!transform.stackErrors().empty())
BOOST_THROW_EXCEPTION(transform.stackErrors().front());
} }

View File

@ -187,7 +187,7 @@ BOOST_AUTO_TEST_CASE(nested)
x := add(add(add(add(add(add(add(add(add(add(add(add(x, r12), r11), r10), r9), r8), r7), r6), r5), r4), r3), r2), r1) x := add(add(add(add(add(add(add(add(add(add(add(add(x, r12), r11), r10), r9), r8), r7), r6), r5), r4), r3), r2), r1)
} }
})"); })");
BOOST_CHECK_EQUAL(out, "h: 9 "); BOOST_CHECK_EQUAL(out, "h: 9 g: 5 f: 5 ");
} }
BOOST_AUTO_TEST_CASE(also_in_outer_block) BOOST_AUTO_TEST_CASE(also_in_outer_block)
@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(also_in_outer_block)
function g(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19) -> w, v { function g(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19) -> w, v {
} }
})"); })");
BOOST_CHECK_EQUAL(out, ": 9 "); BOOST_CHECK_EQUAL(out, "g: 5 : 9 ");
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()