From 579e4b5a6949581eb9cac3cc1be2114b804c7fff Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 8 Jul 2020 12:54:52 +0200 Subject: [PATCH] Report all stack errors in the EVM code transform. --- libyul/CompilabilityChecker.cpp | 9 +---- libyul/backends/evm/AsmCodeGen.cpp | 12 ++---- libyul/backends/evm/EVMCodeTransform.cpp | 47 +++++++++-------------- libyul/backends/evm/EVMObjectCompiler.cpp | 3 +- test/libyul/CompilabilityChecker.cpp | 4 +- 5 files changed, 27 insertions(+), 48 deletions(-) diff --git a/libyul/CompilabilityChecker.cpp b/libyul/CompilabilityChecker.cpp index 344266a12..0d80a510f 100644 --- a/libyul/CompilabilityChecker.cpp +++ b/libyul/CompilabilityChecker.cpp @@ -59,14 +59,7 @@ map CompilabilityChecker::run( builtinContext, _optimizeStackAllocation ); - try - { - transform(*_object.code); - } - catch (StackTooDeepError const&) - { - yulAssert(!transform.stackErrors().empty(), "Got stack too deep exception that was not stored."); - } + transform(*_object.code); std::map functions; for (StackTooDeepError const& error: transform.stackErrors()) diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 327ce8895..8c6f672ab 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -231,18 +231,12 @@ void CodeGenerator::assemble( _identifierAccess, _useNamedLabelsForFunctions ); - try - { - transform(_parsedData); - } - catch (StackTooDeepError const& _e) - { + transform(_parsedData); + if (!transform.stackErrors().empty()) assertThrow( false, langutil::StackTooDeepError, "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."); } diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 041e00380..0287f585d 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -435,31 +435,24 @@ void CodeTransform::operator()(FunctionDefinition const& _function) m_context->functionExitPoints.push( 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( - m_assembly, - m_info, - _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(height)); + if (stackError.functionName.empty()) + stackError.functionName = _function.name; + m_stackErrors.emplace_back(std::move(stackError)); } m_assembly.appendLabel(m_context->functionExitPoints.top().label); @@ -605,9 +598,6 @@ void CodeTransform::operator()(Block const& _block) finalizeBlock(_block, blockStartStackHeight); m_scope = originalScope; - - if (!m_stackErrors.empty()) - BOOST_THROW_EXCEPTION(m_stackErrors.front()); } 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) + " 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; } diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index 6463b4a46..685ca517e 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -59,5 +59,6 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) // which should be native to this part of the code. CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize, m_evm15}; transform(*_object.code); - yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown."); + if (!transform.stackErrors().empty()) + BOOST_THROW_EXCEPTION(transform.stackErrors().front()); } diff --git a/test/libyul/CompilabilityChecker.cpp b/test/libyul/CompilabilityChecker.cpp index 51aefc610..ad1a6fd5e 100644 --- a/test/libyul/CompilabilityChecker.cpp +++ b/test/libyul/CompilabilityChecker.cpp @@ -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) } })"); - BOOST_CHECK_EQUAL(out, "h: 9 "); + BOOST_CHECK_EQUAL(out, "h: 9 g: 5 f: 5 "); } 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 { } })"); - BOOST_CHECK_EQUAL(out, ": 9 "); + BOOST_CHECK_EQUAL(out, "g: 5 : 9 "); } BOOST_AUTO_TEST_SUITE_END()