diff options
author | Valentin Wüstholz <wuestholz@gmail.com> | 2017-01-23 03:49:12 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2017-01-26 23:39:07 +0800 |
commit | 9bcbd93ac59a19320fd56e27c58a6283f2450666 (patch) | |
tree | cf102bce6745c1e771dcacbd83a6e850a09c0054 | |
parent | 102fd7ee5daeb7d7a7bb1254cf0ce71a23ad1220 (diff) | |
download | dexon-solidity-9bcbd93ac59a19320fd56e27c58a6283f2450666.tar.gz dexon-solidity-9bcbd93ac59a19320fd56e27c58a6283f2450666.tar.zst dexon-solidity-9bcbd93ac59a19320fd56e27c58a6283f2450666.zip |
Change translation of implicit throws (issue #1589).
This adds a new invalid instruction that is used for encoding
implicit throws that are emitted by the compiler. This makes it
possible to distinguish such runtime errors from user-provided,
explicit throws.
-rw-r--r-- | libevmasm/Instruction.cpp | 2 | ||||
-rw-r--r-- | libevmasm/Instruction.h | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ArrayUtils.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 12 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.h | 4 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 6 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 8 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 12 | ||||
-rw-r--r-- | test/libsolidity/Assembly.cpp | 4 | ||||
-rw-r--r-- | test/libsolidity/SolidityExpressionCompiler.cpp | 14 |
10 files changed, 49 insertions, 17 deletions
diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index 17445c59..ea5b5a10 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -154,6 +154,7 @@ const std::map<std::string, Instruction> dev::solidity::c_instructions = { "LOG2", Instruction::LOG2 }, { "LOG3", Instruction::LOG3 }, { "LOG4", Instruction::LOG4 }, + { "INVALID", Instruction::INVALID }, { "CREATE", Instruction::CREATE }, { "CALL", Instruction::CALL }, { "CALLCODE", Instruction::CALLCODE }, @@ -288,6 +289,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo = { Instruction::LOG2, { "LOG2", 0, 4, 0, true, Tier::Special } }, { Instruction::LOG3, { "LOG3", 0, 5, 0, true, Tier::Special } }, { Instruction::LOG4, { "LOG4", 0, 6, 0, true, Tier::Special } }, + { Instruction::INVALID, { "INVALID", 0, 0, 0, true, Tier::Zero } }, { Instruction::CREATE, { "CREATE", 0, 3, 1, true, Tier::Special } }, { Instruction::CALL, { "CALL", 0, 7, 1, true, Tier::Special } }, { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true, Tier::Special } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 2dd451cd..7432f04d 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -171,6 +171,8 @@ enum class Instruction: uint8_t LOG3, ///< Makes a log entry; 3 topics. LOG4, ///< Makes a log entry; 4 topics. + INVALID = 0xef, ///< invalid instruction for expressing runtime errors (e.g., division-by-zero) + CREATE = 0xf0, ///< create a new account with associated code CALL, ///< message-call into an account CALLCODE, ///< message-call with another account's code only diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 4d100d1d..bdd29abd 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -901,7 +901,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c // check out-of-bounds access m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; // out-of-bounds access throws exception - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } if (location == DataLocation::CallData && _arrayType.isDynamicallySized()) // remove length if present diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index e26f96e8..45450350 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -215,6 +215,18 @@ CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpTy return *this << item; } +CompilerContext& CompilerContext::appendInvalid() +{ + return *this << Instruction::INVALID; +} + +CompilerContext& CompilerContext::appendConditionalInvalid() +{ + eth::AssemblyItem falseTag = appendConditionalJump(); + eth::AssemblyItem endTag = appendJumpToNew(); + return *this << falseTag << Instruction::INVALID << endTag; +} + void CompilerContext::resetVisitedNodes(ASTNode const* _node) { stack<ASTNode const*> newStack; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index f024b010..58d6cb2a 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -127,6 +127,10 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); + /// Appends an INVALID instruction + CompilerContext& appendInvalid(); + /// Appends a conditional INVALID instruction + CompilerContext& appendConditionalInvalid(); /// Returns an "ErrorTag" eth::AssemblyItem errorTag() { return m_asm->errorTag(); } /// Appends a JUMP to a specific tag diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index caf3b1ac..67877bbf 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -468,7 +468,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack); solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); enumOverflowCheckPending = false; } break; @@ -497,7 +497,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); enumOverflowCheckPending = false; } else if (targetTypeCategory == Type::Category::FixedPoint) @@ -807,7 +807,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) { if (funType->location() == FunctionType::Location::Internal) { - m_context << m_context.errorTag(); + m_context.appendInvalid(); return; } } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 9dc1fb37..56d03a05 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -106,7 +106,7 @@ void ContractCompiler::appendCallValueCheck() { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _contract) @@ -271,7 +271,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); } else - m_context.appendJumpTo(m_context.errorTag()); + m_context.appendInvalid(); for (auto const& it: interfaceFunctions) { @@ -918,7 +918,9 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() a << Instruction::DELEGATECALL; //Propagate error condition (if DELEGATECALL pushes 0 on stack). a << Instruction::ISZERO; - a.appendJumpI(a.errorTag()); + eth::AssemblyItem falseTag = a.appendJumpI(); + eth::AssemblyItem endTag = a.appendJump().tag(); + a << falseTag << Instruction::INVALID << endTag; //@todo adjust for larger return values, make this dynamic. a << u256(0x20) << u256(0) << Instruction::RETURN; return make_shared<eth::Assembly>(a); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index bda4e04d..b66a3e12 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -585,7 +585,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << Instruction::CREATE; // Check if zero (out of stack or not enough balance). m_context << Instruction::DUP1 << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); if (function.valueSet()) m_context << swapInstruction(1) << Instruction::POP; break; @@ -1234,7 +1234,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) m_context << u256(fixedBytesType.numBytes()); m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; // out-of-bounds access throws exception - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); m_context << Instruction::BYTE; m_context << (u256(1) << (256 - 8)) << Instruction::MUL; @@ -1416,7 +1416,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty { // Test for division by zero m_context << Instruction::DUP2 << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); if (_operator == Token::Div) m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV); @@ -1477,7 +1477,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co if (c_amountSigned) { m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } switch (_operator) @@ -1663,7 +1663,7 @@ void ExpressionCompiler::appendExternalFunctionCall( if (funKind == FunctionKind::External || funKind == FunctionKind::CallCode || funKind == FunctionKind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); existenceChecked = true; } @@ -1699,7 +1699,7 @@ void ExpressionCompiler::appendExternalFunctionCall( { //Propagate error condition (if CALL pushes 0 on stack). m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalInvalid(); } utils().popStackSlots(remainsSize); diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 155dd5c9..aed3c854 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -116,8 +116,8 @@ BOOST_AUTO_TEST_CASE(location_test) shared_ptr<string const> n = make_shared<string>(""); AssemblyItems items = compileContract(sourceCode); vector<SourceLocation> locations = - vector<SourceLocation>(18, SourceLocation(2, 75, n)) + - vector<SourceLocation>(27, SourceLocation(20, 72, n)) + + vector<SourceLocation>(17, SourceLocation(2, 75, n)) + + vector<SourceLocation>(32, SourceLocation(20, 72, n)) + vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} + vector<SourceLocation>(2, SourceLocation(58, 67, n)) + vector<SourceLocation>(3, SourceLocation(20, 72, n)); diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 0c5a09c3..ca630169 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -337,13 +337,23 @@ BOOST_AUTO_TEST_CASE(arithmetics) byte(Instruction::ADD), byte(Instruction::DUP2), byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x0, + byte(Instruction::PUSH1), 0x1e, byte(Instruction::JUMPI), + byte(Instruction::PUSH1), 0x20, + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + byte(Instruction::INVALID), + byte(Instruction::JUMPDEST), byte(Instruction::MOD), byte(Instruction::DUP2), byte(Instruction::ISZERO), - byte(Instruction::PUSH1), 0x0, + byte(Instruction::PUSH1), 0x2a, byte(Instruction::JUMPI), + byte(Instruction::PUSH1), 0x2c, + byte(Instruction::JUMP), + byte(Instruction::JUMPDEST), + byte(Instruction::INVALID), + byte(Instruction::JUMPDEST), byte(Instruction::DIV), byte(Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); |