From 9db5fb5bb6ff978123368a4406b71f1c5e249ab8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 6 Jun 2015 01:04:55 +0200 Subject: [PATCH] Improved "Stack too deep" error message. Closes #2080. --- libevmasm/CommonSubexpressionEliminator.cpp | 4 ++-- libsolidity/ArrayUtils.cpp | 5 +++- libsolidity/Compiler.cpp | 2 +- libsolidity/CompilerUtils.cpp | 11 +++++---- libsolidity/ExpressionCompiler.cpp | 2 +- libsolidity/LValue.cpp | 26 +++++++++++++++------ 6 files changed, 34 insertions(+), 16 deletions(-) diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index b2fa73116..a441bd8bb 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -428,7 +428,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); int instructionNum = 1 + m_stackHeight - _fromPosition; - assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); appendItem(AssemblyItem(dupInstruction(instructionNum), _location)); m_stack[m_stackHeight] = m_stack[_fromPosition]; @@ -441,7 +441,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons if (_fromPosition == m_stackHeight) return; int instructionNum = m_stackHeight - _fromPosition; - assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); + assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); appendItem(AssemblyItem(swapInstruction(instructionNum), _location)); diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 531ab8af1..b770b815c 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -168,7 +168,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons else solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString()); // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] ... - solAssert(2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, "Stack too deep."); + solAssert( + 2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, + "Stack too deep, try removing local variables." + ); // fetch target storage reference m_context << eth::dupInstruction(2 + byteOffsetSize + sourceBaseType->getSizeOnStack()); if (haveByteOffsetTarget) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 40ed1fd8e..0a75e55a9 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -367,7 +367,7 @@ bool Compiler::visit(FunctionDefinition const& _function) stackLayout.push_back(i); stackLayout += vector(c_localVariablesSize, -1); - solAssert(stackLayout.size() <= 17, "Stack too deep."); + solAssert(stackLayout.size() <= 17, "Stack too deep, try removing local variables."); while (stackLayout.back() != int(stackLayout.size() - 1)) if (stackLayout.back() < 0) { diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index e3d8f7f90..3549ef98d 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -142,22 +142,25 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) solAssert(stackPosition >= size, "Variable size and position mismatch."); // move variable starting from its top end in the stack if (stackPosition - size + 1 > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_variable.getLocation()) - << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_variable.getLocation()) << + errinfo_comment("Stack too deep, try removing local variables.") + ); for (unsigned i = 0; i < size; ++i) m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; } void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) { - solAssert(_stackDepth <= 16, "Stack too deep."); + solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables."); for (unsigned i = 0; i < _itemSize; ++i) m_context << eth::dupInstruction(_stackDepth); } void CompilerUtils::moveToStackTop(unsigned _stackDepth) { - solAssert(_stackDepth <= 15, "Stack too deep."); + solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables."); for (unsigned i = 0; i < _stackDepth; ++i) m_context << eth::swapInstruction(1 + i); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index bac967d84..ba80a8ea2 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -263,7 +263,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); if (lvalueSize > 0) { - solAssert(itemSize + lvalueSize <= 16, "Stack too deep."); + solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); // value [lvalue_ref] updated_value for (unsigned i = 0; i < itemSize; ++i) m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; diff --git a/libsolidity/LValue.cpp b/libsolidity/LValue.cpp index 38efb2a73..b684e55a1 100644 --- a/libsolidity/LValue.cpp +++ b/libsolidity/LValue.cpp @@ -42,8 +42,11 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const { unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); for (unsigned i = 0; i < m_size; ++i) m_context << eth::dupInstruction(stackPos + 1); } @@ -52,8 +55,11 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo { unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); else if (stackDiff > 0) for (unsigned i = 0; i < m_size; ++i) m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; @@ -65,8 +71,11 @@ void StackVariable::setToZero(SourceLocation const& _location, bool) const { unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackDiff > 16) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); + BOOST_THROW_EXCEPTION( + CompilerError() << + errinfo_sourceLocation(_location) << + errinfo_comment("Stack too deep, try removing local variables.") + ); solAssert(stackDiff >= m_size - 1, ""); for (unsigned i = 0; i < m_size; ++i) m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) @@ -204,7 +213,10 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc // stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_member_ref source_member_off StorageItem(m_context, *memberType).retrieveValue(_location, true); // stack: source_ref source_off target_ref target_off member_offset source_value... - solAssert(4 + memberType->getSizeOnStack() <= 16, "Stack too deep."); + solAssert( + 4 + memberType->getSizeOnStack() <= 16, + "Stack too deep, try removing local varibales." + ); m_context << eth::dupInstruction(4 + memberType->getSizeOnStack()) << eth::dupInstruction(3 + memberType->getSizeOnStack()) << eth::Instruction::ADD