From b6c839e817a35d51f44847558b8f1f4cf0ec1737 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 12:30:29 +0200 Subject: [PATCH 1/4] Disallow indexed reference types in events when using ABIEncoderV2 --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 10 ++++++++++ .../syntaxTests/events/event_array_indexed_v2.sol | 7 +++++++ test/libsolidity/syntaxTests/events/event_array_v2.sol | 6 ++++++ .../events/event_nested_array_indexed_v2.sol | 7 +++++++ .../syntaxTests/events/event_nested_array_v2.sol | 6 ++++++ .../syntaxTests/events/event_struct_indexed_v2.sol | 8 ++++++++ .../libsolidity/syntaxTests/events/event_struct_v2.sol | 7 +++++++ 8 files changed, 52 insertions(+) create mode 100644 test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_array_v2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_nested_array_v2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_struct_v2.sol diff --git a/Changelog.md b/Changelog.md index 177a071b0..5fcf134b2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -108,6 +108,7 @@ Bugfixes: * Type Checker: Fix crashes in erroneous tuple assignments in which the type of the right hand side cannot be determined. * Type Checker: Fix freeze for negative fixed-point literals very close to ``0``, such as ``-1e-100``. * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values. + * Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values. * Type System: Allow arbitrary exponents for literals with a mantissa of zero. ### 0.4.24 (2018-05-16) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 43e894e5d..b1ab6f977 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -895,7 +895,17 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) for (ASTPointer const& var: _eventDef.parameters()) { if (var->isIndexed()) + { numIndexed++; + if ( + _eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) + && dynamic_cast(type(*var).get()) + ) + m_errorReporter.typeError( + var->location(), + "Reference types cannot be indexed." + ); + } if (!type(*var)->canLiveOutsideStorage()) m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) diff --git a/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol new file mode 100644 index 000000000..6b126db4a --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol @@ -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): Reference types cannot be indexed. diff --git a/test/libsolidity/syntaxTests/events/event_array_v2.sol b/test/libsolidity/syntaxTests/events/event_array_v2.sol new file mode 100644 index 000000000..9ccd9fc90 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_array_v2.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol new file mode 100644 index 000000000..5c556125e --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol @@ -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): Reference types cannot be indexed. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol new file mode 100644 index 000000000..efc7439ec --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol new file mode 100644 index 000000000..8d2d4f8c4 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol @@ -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): Reference types cannot be indexed. diff --git a/test/libsolidity/syntaxTests/events/event_struct_v2.sol b/test/libsolidity/syntaxTests/events/event_struct_v2.sol new file mode 100644 index 000000000..97ca61b61 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct_v2.sol @@ -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. From c3d3ae80fa59df3a134141ed75f4d195984960fd Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 16:54:13 +0200 Subject: [PATCH 2/4] Add end to end tests --- test/libsolidity/SolidityEndToEndTest.cpp | 203 ++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 8a334e5e7..ce3c43242 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3937,6 +3937,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"( From faed71c6b1235a808a2c87026b345a637238e4a9 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 16:58:41 +0200 Subject: [PATCH 3/4] Review suggestions --- libsolidity/analysis/TypeChecker.cpp | 6 +++--- .../syntaxTests/events/event_array_indexed_v2.sol | 2 +- .../syntaxTests/events/event_nested_array_indexed_v2.sol | 2 +- .../syntaxTests/events/event_struct_indexed_v2.sol | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b1ab6f977..c737fe417 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -898,12 +898,12 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) { numIndexed++; if ( - _eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) - && dynamic_cast(type(*var).get()) + _eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && + dynamic_cast(type(*var).get()) ) m_errorReporter.typeError( var->location(), - "Reference types cannot be indexed." + "Indexed reference types cannot yet be used with ABIEncoderV2." ); } if (!type(*var)->canLiveOutsideStorage()) diff --git a/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol index 6b126db4a..aaf6028a8 100644 --- a/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol +++ b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol @@ -4,4 +4,4 @@ contract c { } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. -// TypeError: (59-65): Reference types cannot be indexed. +// TypeError: (59-65): Indexed reference types cannot yet be used with ABIEncoderV2. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol index 5c556125e..ffae5b9cc 100644 --- a/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol +++ b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol @@ -4,4 +4,4 @@ contract c { } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. -// TypeError: (59-67): Reference types cannot be indexed. +// TypeError: (59-67): Indexed reference types cannot yet be used with ABIEncoderV2. diff --git a/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol index 8d2d4f8c4..a8e0837f8 100644 --- a/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol +++ b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol @@ -5,4 +5,4 @@ contract c { } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. -// TypeError: (85-86): Reference types cannot be indexed. +// TypeError: (85-86): Indexed reference types cannot yet be used with ABIEncoderV2. From c00db3c247dd2aa296650045b995cbfa87ba2324 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 17:10:02 +0200 Subject: [PATCH 4/4] Bug list entry --- docs/bugs.json | 8 ++++++++ docs/bugs_by_version.json | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/bugs.json b/docs/bugs.json index 3f20077f3..839ea128c 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -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.5.0", + "severity": "very low" + }, { "name": "NestedArrayFunctionCallDecoder", "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index b400121fc..560b6fa9e 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -412,6 +412,7 @@ }, "0.4.17": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], @@ -419,12 +420,14 @@ }, "0.4.18": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" ], "released": "2017-10-18" }, "0.4.19": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" ], "released": "2017-11-30" @@ -445,28 +448,35 @@ }, "0.4.20": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" ], "released": "2018-02-14" }, "0.4.21": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" ], "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": {