Merge pull request #4920 from ethereum/disallow_indexed_ref_v2_for_0_425

Disallow indexed reference types in events when using ABIEncoderV2 (backported)
This commit is contained in:
chriseth 2018-09-10 12:59:35 +02:00 committed by GitHub
commit a1848ac947
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 283 additions and 6 deletions

View File

@ -1,6 +1,7 @@
### 0.4.25 (unreleased)
Bugfixes:
* Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values.
* Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values.
### 0.4.24 (2018-05-16)

View File

@ -1,4 +1,12 @@
[
{
"name": "EventStructWrongData",
"summary": "Using structs in events logged wrong data.",
"description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.",
"introduced": "0.4.17",
"fixed": "0.4.25",
"severity": "very low"
},
{
"name": "OneOfTwoConstructorsSkipped",
"summary": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.",

View File

@ -389,16 +389,21 @@
},
"0.4.17": {
"bugs": [
"EventStructWrongData",
"ZeroFunctionSelector"
],
"released": "2017-09-21"
},
"0.4.18": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2017-10-18"
},
"0.4.19": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2017-11-30"
},
"0.4.2": {
@ -415,25 +420,34 @@
"released": "2016-09-17"
},
"0.4.20": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2018-02-14"
},
"0.4.21": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2018-03-07"
},
"0.4.22": {
"bugs": [
"EventStructWrongData",
"OneOfTwoConstructorsSkipped"
],
"released": "2018-04-16"
},
"0.4.23": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2018-04-19"
},
"0.4.24": {
"bugs": [],
"bugs": [
"EventStructWrongData"
],
"released": "2018-05-16"
},
"0.4.3": {

View File

@ -869,7 +869,17 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
for (ASTPointer<VariableDeclaration> const& var: _eventDef.parameters())
{
if (var->isIndexed())
{
numIndexed++;
if (
_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
dynamic_cast<ReferenceType const*>(type(*var).get())
)
m_errorReporter.typeError(
var->location(),
"Indexed reference types cannot yet be used with ABIEncoderV2."
);
}
if (!type(*var)->canLiveOutsideStorage())
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
if (!type(*var)->interfaceType(false))

View File

@ -3516,6 +3516,209 @@ BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage)
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(event_struct_memory_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; }
event E(S);
function createEvent(uint x) public {
emit E(S(x));
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(x));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))")));
}
BOOST_AUTO_TEST_CASE(event_struct_storage_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
struct S { uint a; }
event E(S);
S s;
function createEvent(uint x) public {
s.a = x;
emit E(s);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(x));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory)
{
char const* sourceCode = R"(
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
event E(uint[]);
function createEvent(uint x) public {
uint[] memory arr = new uint[](3);
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
event E(uint[][]);
function createEvent(uint x) public {
uint[][] memory arr = new uint[][](2);
arr[0] = new uint[](2);
arr[1] = new uint[](2);
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_storage)
{
char const* sourceCode = R"(
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
arr.length = 3;
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
event E(uint[]);
uint[] arr;
function createEvent(uint x) public {
arr.length = 3;
arr[0] = x;
arr[1] = x + 1;
arr[2] = x + 2;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])")));
}
BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2)
{
char const* sourceCode = R"(
pragma experimental ABIEncoderV2;
contract C {
event E(uint[][]);
uint[][] arr;
function createEvent(uint x) public {
arr.length = 2;
arr[0].length = 2;
arr[1].length = 2;
arr[0][0] = x;
arr[0][1] = x + 1;
arr[1][0] = x + 2;
arr[1][1] = x + 3;
emit E(arr);
}
}
)";
compileAndRun(sourceCode);
u256 x(42);
callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])")));
}
BOOST_AUTO_TEST_CASE(event_indexed_string)
{
char const* sourceCode = R"(

View File

@ -0,0 +1,7 @@
pragma experimental ABIEncoderV2;
contract c {
event E(uint[] indexed);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (59-65): Indexed reference types cannot yet be used with ABIEncoderV2.

View File

@ -0,0 +1,6 @@
pragma experimental ABIEncoderV2;
contract c {
event E(uint[]);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.

View File

@ -0,0 +1,7 @@
pragma experimental ABIEncoderV2;
contract c {
event E(uint[][] indexed);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (59-67): Indexed reference types cannot yet be used with ABIEncoderV2.

View File

@ -0,0 +1,6 @@
pragma experimental ABIEncoderV2;
contract c {
event E(uint[][]);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.

View File

@ -0,0 +1,8 @@
pragma experimental ABIEncoderV2;
contract c {
struct S { uint a ; }
event E(S indexed);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (85-86): Indexed reference types cannot yet be used with ABIEncoderV2.

View File

@ -0,0 +1,7 @@
pragma experimental ABIEncoderV2;
contract c {
struct S { uint a ; }
event E(S);
}
// ----
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.