Make function calls throw if target does not have code.

Low-level calls still just execute and will actually report "success".
This allows `x.call.value(y)()` for x being a non-contract account.
This commit is contained in:
chriseth 2016-08-07 19:46:11 +02:00
parent e7683f4722
commit 774bb8ab3b
3 changed files with 37 additions and 0 deletions

View File

@ -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

View File

@ -1517,6 +1517,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

View File

@ -6896,6 +6896,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()
}