mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2679 from ethereum/delegatecall
.delegatecall() should always return a boolean of execution status
This commit is contained in:
commit
bd9e91085b
@ -3,6 +3,7 @@
|
|||||||
Features:
|
Features:
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
* Code Generator: ``.delegatecall()`` should always return execution outcome.
|
||||||
* Code Generator: Provide "new account gas" for low-level ``callcode`` and ``delegatecall``.
|
* Code Generator: Provide "new account gas" for low-level ``callcode`` and ``delegatecall``.
|
||||||
|
|
||||||
### 0.4.14 (2017-07-31)
|
### 0.4.14 (2017-07-31)
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"name": "DelegateCallReturnValue",
|
||||||
|
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
|
||||||
|
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successuful.",
|
||||||
|
"introduced": "0.3.0",
|
||||||
|
"fixed": "0.4.15",
|
||||||
|
"severity": "low"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "ECRecoverMalformedInput",
|
"name": "ECRecoverMalformedInput",
|
||||||
"summary": "The ecrecover() builtin can return garbage for malformed input.",
|
"summary": "The ecrecover() builtin can return garbage for malformed input.",
|
||||||
|
@ -182,6 +182,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.0": {
|
"0.3.0": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -198,6 +199,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.1": {
|
"0.3.1": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -213,6 +215,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.2": {
|
"0.3.2": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -228,6 +231,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.3": {
|
"0.3.3": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -242,6 +246,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.4": {
|
"0.3.4": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -256,6 +261,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.5": {
|
"0.3.5": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -270,6 +276,7 @@
|
|||||||
},
|
},
|
||||||
"0.3.6": {
|
"0.3.6": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -282,6 +289,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.0": {
|
"0.4.0": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -294,6 +302,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.1": {
|
"0.4.1": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -306,6 +315,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.10": {
|
"0.4.10": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction"
|
"ConstantOptimizerSubtraction"
|
||||||
@ -314,6 +324,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.11": {
|
"0.4.11": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral"
|
"SkipEmptyStringLiteral"
|
||||||
],
|
],
|
||||||
@ -321,22 +332,27 @@
|
|||||||
},
|
},
|
||||||
"0.4.12": {
|
"0.4.12": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput"
|
"ECRecoverMalformedInput"
|
||||||
],
|
],
|
||||||
"released": "2017-07-03"
|
"released": "2017-07-03"
|
||||||
},
|
},
|
||||||
"0.4.13": {
|
"0.4.13": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput"
|
"ECRecoverMalformedInput"
|
||||||
],
|
],
|
||||||
"released": "2017-07-06"
|
"released": "2017-07-06"
|
||||||
},
|
},
|
||||||
"0.4.14": {
|
"0.4.14": {
|
||||||
"bugs": [],
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue"
|
||||||
|
],
|
||||||
"released": "2017-07-31"
|
"released": "2017-07-31"
|
||||||
},
|
},
|
||||||
"0.4.2": {
|
"0.4.2": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -348,6 +364,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.3": {
|
"0.4.3": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -358,6 +375,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.4": {
|
"0.4.4": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -367,6 +385,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.5": {
|
"0.4.5": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -377,6 +396,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.6": {
|
"0.4.6": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction",
|
"ConstantOptimizerSubtraction",
|
||||||
@ -386,6 +406,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.7": {
|
"0.4.7": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction"
|
"ConstantOptimizerSubtraction"
|
||||||
@ -394,6 +415,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.8": {
|
"0.4.8": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction"
|
"ConstantOptimizerSubtraction"
|
||||||
@ -402,6 +424,7 @@
|
|||||||
},
|
},
|
||||||
"0.4.9": {
|
"0.4.9": {
|
||||||
"bugs": [
|
"bugs": [
|
||||||
|
"DelegateCallReturnValue",
|
||||||
"ECRecoverMalformedInput",
|
"ECRecoverMalformedInput",
|
||||||
"SkipEmptyStringLiteral",
|
"SkipEmptyStringLiteral",
|
||||||
"ConstantOptimizerSubtraction"
|
"ConstantOptimizerSubtraction"
|
||||||
|
@ -393,6 +393,9 @@ When exceptions happen in a sub-call, they "bubble up" (i.e. exceptions are reth
|
|||||||
and the low-level functions ``call``, ``delegatecall`` and ``callcode`` -- those return ``false`` in case
|
and the low-level functions ``call``, ``delegatecall`` and ``callcode`` -- those return ``false`` in case
|
||||||
of an exception instead of "bubbling up".
|
of an exception instead of "bubbling up".
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
The low-level ``call``, ``delegatecall`` and ``callcode`` will return success if the calling account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired.
|
||||||
|
|
||||||
Catching exceptions is not yet possible.
|
Catching exceptions is not yet possible.
|
||||||
|
|
||||||
In the following example, you can see how ``require`` can be used to easily check conditions on inputs
|
In the following example, you can see how ``require`` can be used to easily check conditions on inputs
|
||||||
|
@ -1560,7 +1560,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
||||||
|
|
||||||
auto funKind = _functionType.kind();
|
auto funKind = _functionType.kind();
|
||||||
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode;
|
bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall;
|
||||||
bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
|
bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
|
||||||
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
||||||
|
|
||||||
|
@ -9897,6 +9897,64 @@ BOOST_AUTO_TEST_CASE(inlineasm_empty_let)
|
|||||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0), u256(0)));
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0), u256(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(bare_call_invalid_address)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
/// Calling into non-existant account is successful (creates the account)
|
||||||
|
function f() external constant returns (bool) {
|
||||||
|
return address(0x4242).call();
|
||||||
|
}
|
||||||
|
function g() external constant returns (bool) {
|
||||||
|
return address(0x4242).callcode();
|
||||||
|
}
|
||||||
|
function h() external constant returns (bool) {
|
||||||
|
return address(0x4242).delegatecall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("h()") == encodeArgs(u256(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(delegatecall_return_value)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"DELIMITER(
|
||||||
|
contract C {
|
||||||
|
uint value;
|
||||||
|
function set(uint _value) external {
|
||||||
|
value = _value;
|
||||||
|
}
|
||||||
|
function get() external constant returns (uint) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function get_delegated() external constant returns (bool) {
|
||||||
|
return this.delegatecall(bytes4(sha3("get()")));
|
||||||
|
}
|
||||||
|
function assert0() external constant {
|
||||||
|
assert(value == 0);
|
||||||
|
}
|
||||||
|
function assert0_delegated() external constant returns (bool) {
|
||||||
|
return this.delegatecall(bytes4(sha3("assert0()")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)DELIMITER";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0)));
|
||||||
|
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("set(uint256)", u256(1)) == encodeArgs());
|
||||||
|
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(0)));
|
||||||
|
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||||
|
BOOST_CHECK(callContractFunction("set(uint256)", u256(42)) == encodeArgs());
|
||||||
|
BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(42)));
|
||||||
|
BOOST_CHECK(callContractFunction("assert0_delegated()") == encodeArgs(u256(0)));
|
||||||
|
BOOST_CHECK(callContractFunction("get_delegated()") == encodeArgs(u256(1)));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user