From d417618dce14a58101a31471e025d18460b12daf Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 18:38:32 +0100 Subject: [PATCH] Stack height checks and fix. --- libsolidity/Compiler.cpp | 40 +++++++++++++++++++++++++++++++---- libsolidity/Compiler.h | 2 +- libsolidity/CompilerContext.h | 2 +- libsolidity/Types.cpp | 11 ++++++++-- test/SolidityEndToEndTest.cpp | 1 - 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 23014da6c..e691394cb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -34,6 +34,20 @@ using namespace std; namespace dev { namespace solidity { +/** + * Simple helper class to ensure that the stack height is the same at certain places in the code. + */ +class StackHeightChecker +{ +public: + StackHeightChecker(CompilerContext const& _context): + m_context(_context), stackHeight(m_context.getStackHeight()) {} + void check() { solAssert(m_context.getStackHeight() == stackHeight, "I sense a disturbance in the stack."); } +private: + CompilerContext const& m_context; + unsigned stackHeight; +}; + void Compiler::compileContract(ContractDefinition const& _contract, map const& _contracts) { @@ -340,6 +354,8 @@ bool Compiler::visit(FunctionDefinition const& _function) bool Compiler::visit(IfStatement const& _ifStatement) { + StackHeightChecker checker(m_context); + compileExpression(_ifStatement.getCondition()); eth::AssemblyItem trueTag = m_context.appendConditionalJump(); if (_ifStatement.getFalseStatement()) @@ -348,11 +364,15 @@ bool Compiler::visit(IfStatement const& _ifStatement) m_context << trueTag; _ifStatement.getTrueStatement().accept(*this); m_context << endTag; + + checker.check(); return false; } bool Compiler::visit(WhileStatement const& _whileStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -370,11 +390,15 @@ bool Compiler::visit(WhileStatement const& _whileStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } bool Compiler::visit(ForStatement const& _forStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -404,6 +428,8 @@ bool Compiler::visit(ForStatement const& _forStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } @@ -438,29 +464,35 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { - if (Expression const* expression = _variableDefinition.getExpression()) + StackHeightChecker checker(m_context); + if (Expression const* expression = _variableDeclarationStatement.getExpression()) { - compileExpression(*expression, _variableDefinition.getDeclaration().getType()); - CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration()); + compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType()); + CompilerUtils(m_context).moveToStackVariable(_variableDeclarationStatement.getDeclaration()); } + checker.check(); return false; } bool Compiler::visit(ExpressionStatement const& _expressionStatement) { + StackHeightChecker checker(m_context); Expression const& expression = _expressionStatement.getExpression(); compileExpression(expression); CompilerUtils(m_context).popStackElement(*expression.getType()); + checker.check(); return false; } bool Compiler::visit(PlaceholderStatement const&) { + StackHeightChecker checker(m_context); ++m_modifierDepth; appendModifierOrFunctionCode(); --m_modifierDepth; + checker.check(); return true; } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 0838512ee..28ab34adb 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -69,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index f202d7f4e..da2e7f4fe 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -48,7 +48,7 @@ public: bytes const& getCompiledContract(ContractDefinition const& _contract) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } - unsigned getStackHeight() { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } + unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 55dedd921..ce51336df 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -833,10 +833,17 @@ string FunctionType::toString() const unsigned FunctionType::getSizeOnStack() const { + Location location = m_location; + if (m_location == Location::SetGas || m_location == Location::SetValue) + { + solAssert(m_returnParameterTypes.size() == 1, ""); + location = dynamic_cast(*m_returnParameterTypes.front()).m_location; + } + unsigned size = 0; - if (m_location == Location::External) + if (location == Location::External) size = 2; - else if (m_location == Location::Internal || m_location == Location::Bare) + else if (location == Location::Internal || location == Location::Bare) size = 1; if (m_gasSet) size++; diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 1f80b1017..20bc81599 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1669,7 +1669,6 @@ BOOST_AUTO_TEST_CASE(value_insane) function test() { h = new helper(); } function sendAmount(uint amount) returns (uint256 bal) { var x1 = h.getBalance.value; - uint someStackElement = 20; var x2 = x1(amount).gas; var x3 = x2(1000).value; return x3(amount + 3)();// overwrite value