diff options
-rw-r--r-- | docs/control-structures.rst | 4 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 7 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 26 |
3 files changed, 37 insertions, 0 deletions
diff --git a/docs/control-structures.rst b/docs/control-structures.rst index a6daccac..5b78d099 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -69,6 +69,10 @@ this does not execute a constructor. We could also have used ``function setFeed( only (locally) sets the value and amount of gas sent with the function call and only the parentheses at the end perform the actual call. +Function calls cause exceptions if the called contract does not exist (in the +sense that the account does not contain code) or if the called contract itself +throws an exception or goes out of gas. + .. warning:: Any interaction with another contract imposes a potential danger, especially if the source code of the contract is not known in advance. The current diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4695ff96..4a81e27d 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1524,6 +1524,13 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << u256(0); m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); + // Check the the target contract exists (has code) for non-low-level calls. + if (funKind == FunctionKind::External || funKind == FunctionKind::CallCode || funKind == FunctionKind::DelegateCall) + { + m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } + if (_functionType.gasSet()) m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); else diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f20ea2cb..4e6f68b0 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7049,6 +7049,32 @@ BOOST_AUTO_TEST_CASE(failing_ecrecover_invalid_input) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0))); } +BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws) +{ + char const* sourceCode = R"( + contract D { function g(); } + contract C { + D d = D(0x1212); + function f() returns (uint) { + d.g(); + return 7; + } + function g() returns (uint) { + d.g.gas(200)(); + return 7; + } + function h() returns (uint) { + d.call(); // this does not throw (low-level) + return 7; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs()); + BOOST_CHECK(callContractFunction("g()") == encodeArgs()); + BOOST_CHECK(callContractFunction("h()") == encodeArgs(u256(7))); +} + BOOST_AUTO_TEST_SUITE_END() } |