From 507cdf6de20b5c9bc9a0a8de311e9018af552865 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 16:55:53 +0200 Subject: [PATCH 01/25] Set version. --- CMakeLists.txt | 2 +- Changelog.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c05208f2..f30872af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.4.24") +set(PROJECT_VERSION "0.4.25") project(solidity VERSION ${PROJECT_VERSION}) option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF) diff --git a/Changelog.md b/Changelog.md index 6a408ae8c..0ad1b8634 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,6 @@ +### 0.4.25 (unreleased) + + ### 0.4.24 (2018-05-16) Language Features: From c577e043a4d54ac740aab770a6af38d74a7a427d Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 1 Aug 2018 19:01:50 +0200 Subject: [PATCH 02/25] Disallow structs in events without ABIEncoderV2 --- Changelog.md | 2 ++ libsolidity/analysis/TypeChecker.cpp | 10 ++++++++++ test/libsolidity/SolidityABIJSON.cpp | 1 + test/libsolidity/syntaxTests/emit/emit_empty.sol | 7 +++++++ .../syntaxTests/{ => emit}/emit_non_event.sol | 0 .../syntaxTests/events/event_nested_array.sol | 5 +++++ .../syntaxTests/events/event_nested_array_2.sol | 4 ++++ .../events/event_nested_array_in_struct.sol | 6 ++++++ test/libsolidity/syntaxTests/events/event_struct.sol | 6 ++++++ .../syntaxTests/events/event_struct_indexed.sol | 6 ++++++ 10 files changed, 47 insertions(+) create mode 100644 test/libsolidity/syntaxTests/emit/emit_empty.sol rename test/libsolidity/syntaxTests/{ => emit}/emit_non_event.sol (100%) create mode 100644 test/libsolidity/syntaxTests/events/event_nested_array.sol create mode 100644 test/libsolidity/syntaxTests/events/event_nested_array_2.sol create mode 100644 test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol create mode 100644 test/libsolidity/syntaxTests/events/event_struct.sol create mode 100644 test/libsolidity/syntaxTests/events/event_struct_indexed.sol diff --git a/Changelog.md b/Changelog.md index 0ad1b8634..26f7d5e20 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ ### 0.4.25 (unreleased) +Bugfixes: + * 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) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 30302908c..f69808726 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -864,6 +864,7 @@ void TypeChecker::visitManually( bool TypeChecker::visit(EventDefinition const& _eventDef) { + solAssert(_eventDef.visibility() > Declaration::Visibility::Internal, ""); unsigned numIndexed = 0; for (ASTPointer const& var: _eventDef.parameters()) { @@ -873,6 +874,15 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type."); + if ( + !_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && + !typeSupportedByOldABIEncoder(*type(*var)) + ) + m_errorReporter.typeError( + var->location(), + "This type is only supported in the new experimental ABI encoder. " + "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + ); } if (_eventDef.isAnonymous() && numIndexed > 4) m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event."); diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index 107abc26a..3475b0188 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -1036,6 +1036,7 @@ BOOST_AUTO_TEST_CASE(return_structs_with_contracts) BOOST_AUTO_TEST_CASE(event_structs) { char const* text = R"( + pragma experimental ABIEncoderV2; contract C { struct S { uint a; T[] sub; bytes b; } struct T { uint[2] x; } diff --git a/test/libsolidity/syntaxTests/emit/emit_empty.sol b/test/libsolidity/syntaxTests/emit/emit_empty.sol new file mode 100644 index 000000000..819d88fea --- /dev/null +++ b/test/libsolidity/syntaxTests/emit/emit_empty.sol @@ -0,0 +1,7 @@ +contract C { + function f() public { + emit; + } +} +// ---- +// ParserError: (45-46): Expected event name or path. diff --git a/test/libsolidity/syntaxTests/emit_non_event.sol b/test/libsolidity/syntaxTests/emit/emit_non_event.sol similarity index 100% rename from test/libsolidity/syntaxTests/emit_non_event.sol rename to test/libsolidity/syntaxTests/emit/emit_non_event.sol diff --git a/test/libsolidity/syntaxTests/events/event_nested_array.sol b/test/libsolidity/syntaxTests/events/event_nested_array.sol new file mode 100644 index 000000000..70af63b69 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array.sol @@ -0,0 +1,5 @@ +contract c { + event E(uint[][]); +} +// ---- +// TypeError: (25-33): This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_2.sol new file mode 100644 index 000000000..5825650e1 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_2.sol @@ -0,0 +1,4 @@ +contract c { + event E(uint[2][]); +} +// ---- diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol b/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol new file mode 100644 index 000000000..fd59e9624 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol @@ -0,0 +1,6 @@ +contract c { + struct S { uint x; uint[][] arr; } + event E(S); +} +// ---- +// TypeError: (61-62): This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_struct.sol b/test/libsolidity/syntaxTests/events/event_struct.sol new file mode 100644 index 000000000..c955dc5eb --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct.sol @@ -0,0 +1,6 @@ +contract c { + struct S { uint a ; } + event E(S); +} +// ---- +// TypeError: (51-52): This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_struct_indexed.sol b/test/libsolidity/syntaxTests/events/event_struct_indexed.sol new file mode 100644 index 000000000..69ee50174 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct_indexed.sol @@ -0,0 +1,6 @@ +contract c { + struct S { uint a ; } + event E(S indexed); +} +// ---- +// TypeError: (51-52): This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature. From 768ea5b0bee99aee6d74600ec37b2cdea906c77f Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 12:30:29 +0200 Subject: [PATCH 03/25] 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 26f7d5e20..6397b23bc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index f69808726..f786a83d5 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -869,7 +869,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 bc6366fd5231b1542e50acb9519535903134a44a Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 16:54:13 +0200 Subject: [PATCH 04/25] 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 1efcfde0b..a4b597616 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -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"( From 13c8bb1c8920b6ea507688e24adb68e3bf0aed9f Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 16:58:41 +0200 Subject: [PATCH 05/25] 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 f786a83d5..2062458ef 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -872,12 +872,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 409b20f204df74b24d77d9d88ea0fc9436c58d61 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 15 Aug 2018 17:10:02 +0200 Subject: [PATCH 06/25] Bug list entry --- docs/bugs.json | 8 ++++++++ docs/bugs_by_version.json | 26 ++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/bugs.json b/docs/bugs.json index b464be18a..8eae2af37 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": "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.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 2fe1d2266..00531b9e2 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -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": { From 99022216cd19ecb777bf20c4bfff6fd12395c12e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 16:59:53 +0200 Subject: [PATCH 07/25] Change "fixed" date. --- docs/bugs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bugs.json b/docs/bugs.json index 8eae2af37..423c314d5 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -4,7 +4,7 @@ "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", + "fixed": "0.4.25", "severity": "very low" }, { From f531dd9fa0cfad50fef4e17c4c734e91187debfd Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 4 Sep 2018 12:09:37 +0200 Subject: [PATCH 08/25] Use wildcards for MSVC version in scripts/release.bat. --- scripts/release.bat | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scripts/release.bat b/scripts/release.bat index be95b35e4..b15b49b7b 100644 --- a/scripts/release.bat +++ b/scripts/release.bat @@ -32,12 +32,9 @@ set VERSION=%2 IF "%VERSION%"=="2015" ( set "DLLS=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.CRT\msvc*.dll" ) ELSE ( - - IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\14.13.26020\x86\Microsoft.VC141.CRT\" ( - set "DLLS=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\14.13.26020\x86\Microsoft.VC141.CRT\msvc*.dll" - ) ELSE ( - set "DLLS=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Redist\MSVC\14.13.26020\x86\Microsoft.VC141.CRT\msvc*.dll" - ) + set "DLLS=MSVC_DLLS_NOT_FOUND" + FOR /d %%d IN ("C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Redist\MSVC\*" + "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC\*") DO set "DLLS=%%d\x86\Microsoft.VC141.CRT\msvc*.dll" ) 7z a solidity-windows.zip ^ From 65a439b0fbbd3723f9b6a456cbb9927b3ab5d121 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 5 Sep 2018 22:07:13 +0200 Subject: [PATCH 09/25] Refactor handling of whitespace. --- libsolidity/parsing/Scanner.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 6541f6c2f..64acd411f 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -435,11 +435,6 @@ void Scanner::scanToken() m_nextToken.location.start = sourcePos(); switch (m_char) { - case '\n': - case ' ': - case '\t': - token = selectToken(Token::Whitespace); - break; case '"': case '\'': token = scanString(); From c0d9b492a23537e99495ff84a4a24f55ebd9ebc7 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 11:05:35 +0200 Subject: [PATCH 10/25] This fixes several bugs with regards to line breaks and comments: - any unicode line break (line feed, vertical tab, form feed, carriage return, NEL, LS and PS) is considered to terminate a single-line comment. The line break itself is considered to be the next token after the comment, leading to a parser error if it is not an ascii character (i.e. for NEL, LS and PS). - unterminated multiline comments are considered illegal tokens - '/** /' is considered an unterminated multiline comment (previously, whitespace was allowed before the last '/' --- libsolidity/parsing/Scanner.cpp | 79 +++++++++++++++++++--------- libsolidity/parsing/Scanner.h | 7 ++- test/libsolidity/SolidityScanner.cpp | 8 +++ 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 64acd411f..dbe1f389f 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -243,22 +243,17 @@ bool Scanner::skipWhitespace() return sourcePos() != startPosition; } -bool Scanner::skipWhitespaceExceptLF() +void Scanner::skipWhitespaceExceptUnicodeLinebreak() { - int const startPosition = sourcePos(); - while (isWhiteSpace(m_char) && !isLineTerminator(m_char)) + while (isWhiteSpace(m_char) && !isUnicodeLinebreak()) advance(); - // Return whether or not we skipped any characters. - return sourcePos() != startPosition; } Token::Value Scanner::skipSingleLineComment() { - // The line terminator at the end of the line is not considered - // to be part of the single-line comment; it is recognized - // separately by the lexical grammar and becomes part of the - // stream of input elements for the syntactic grammar - while (!isLineTerminator(m_char)) + // Line terminator is not part of the comment. If it is a + // non-ascii line terminator, it will result in a parser error. + while (!isUnicodeLinebreak()) if (!advance()) break; return Token::Whitespace; @@ -268,7 +263,9 @@ Token::Value Scanner::scanSingleLineDocComment() { LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' at /// - skipWhitespaceExceptLF(); + + skipWhitespaceExceptUnicodeLinebreak(); + while (!isSourcePastEndOfInput()) { if (isLineTerminator(m_char)) @@ -287,6 +284,10 @@ Token::Value Scanner::scanSingleLineDocComment() break; // next line is not a documentation comment, we are done } + else if (isUnicodeLinebreak()) + // Any line terminator that is not '\n' is considered to end the + // comment. + break; addCommentLiteralChar(m_char); advance(); } @@ -321,6 +322,9 @@ Token::Value Scanner::scanMultiLineDocComment() bool endFound = false; bool charsAdded = false; + while (isWhiteSpace(m_char) && !isLineTerminator(m_char)) + advance(); + while (!isSourcePastEndOfInput()) { //handle newlines in multline comments @@ -372,7 +376,7 @@ Token::Value Scanner::scanSlash() if (m_char == '/') { if (!advance()) /* double slash comment directly before EOS */ - return Token::Whitespace; + return Token::Whitespace; else if (m_char == '/') { // doxygen style /// comment @@ -390,24 +394,27 @@ Token::Value Scanner::scanSlash() { // doxygen style /** natspec comment if (!advance()) /* slash star comment before EOS */ - return Token::Whitespace; + return Token::Illegal; else if (m_char == '*') { advance(); //consume the last '*' at /** - skipWhitespaceExceptLF(); - // special case of a closed normal multiline comment - if (!m_source.isPastEndOfInput() && m_source.get(0) == '/') - advance(); //skip the closing slash - else // we actually have a multiline documentation comment + // "/**/" + if (m_char == '/') { - Token::Value comment; - m_nextSkippedComment.location.start = firstSlashPosition; - comment = scanMultiLineDocComment(); - m_nextSkippedComment.location.end = sourcePos(); - m_nextSkippedComment.token = comment; + advance(); //skip the closing slash + return Token::Whitespace; } - return Token::Whitespace; + // we actually have a multiline documentation comment + Token::Value comment; + m_nextSkippedComment.location.start = firstSlashPosition; + comment = scanMultiLineDocComment(); + m_nextSkippedComment.location.end = sourcePos(); + m_nextSkippedComment.token = comment; + if (comment == Token::Illegal) + return Token::Illegal; + else + return Token::Whitespace; } else return skipMultiLineComment(); @@ -670,18 +677,38 @@ bool Scanner::scanEscape() if (!scanHexByte(c)) return false; break; + default: + return false; } addLiteralChar(c); return true; } +bool Scanner::isUnicodeLinebreak() +{ + if (0x0a <= m_char && m_char <= 0x0d) + // line feed, vertical tab, form feed, carriage return + return true; + else if (!m_source.isPastEndOfInput(1) && uint8_t(m_source.get(0)) == 0xc2 && uint8_t(m_source.get(1)) == 0x85) + // NEL - U+0085, C2 85 in utf8 + return true; + else if (!m_source.isPastEndOfInput(2) && uint8_t(m_source.get(0)) == 0xe2 && uint8_t(m_source.get(1)) == 0x80 && ( + uint8_t(m_source.get(2)) == 0xa8 || uint8_t(m_source.get(2)) == 0xa9 + )) + // LS - U+2028, E2 80 A8 in utf8 + // PS - U+2029, E2 80 A9 in utf8 + return true; + else + return false; +} + Token::Value Scanner::scanString() { char const quote = m_char; advance(); // consume quote LiteralScope literal(this, LITERAL_TYPE_STRING); - while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char)) + while (m_char != quote && !isSourcePastEndOfInput() && !isUnicodeLinebreak()) { char c = m_char; advance(); @@ -705,7 +732,7 @@ Token::Value Scanner::scanHexString() char const quote = m_char; advance(); // consume quote LiteralScope literal(this, LITERAL_TYPE_STRING); - while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char)) + while (m_char != quote && !isSourcePastEndOfInput()) { char c = m_char; if (!scanHexByte(c)) diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h index 0adaa6fd2..602532e47 100644 --- a/libsolidity/parsing/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -197,8 +197,8 @@ private: /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); - /// Skips all whitespace except Line feeds and returns true if something was skipped - bool skipWhitespaceExceptLF(); + /// Skips all whitespace that are neither '\r' nor '\n'. + void skipWhitespaceExceptUnicodeLinebreak(); Token::Value skipSingleLineComment(); Token::Value skipMultiLineComment(); @@ -218,6 +218,9 @@ private: /// is scanned. bool scanEscape(); + /// @returns true iff we are currently positioned at a unicode line break. + bool isUnicodeLinebreak(); + /// Return the current source position. int sourcePos() const { return m_source.position(); } bool isSourcePastEndOfInput() const { return m_source.isPastEndOfInput(); } diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp index 020bce7f0..e216ef01b 100644 --- a/test/libsolidity/SolidityScanner.cpp +++ b/test/libsolidity/SolidityScanner.cpp @@ -393,6 +393,14 @@ BOOST_AUTO_TEST_CASE(invalid_hex_literal_nonhex_string) BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); } +BOOST_AUTO_TEST_CASE(invalid_multiline_comment_close) +{ + // This used to parse as "comment", "identifier" + Scanner scanner(CharStream("/** / x")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_SUITE_END() From 30578cad8108216598091ead7dde2acce68924ef Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 16:42:39 +0200 Subject: [PATCH 11/25] Tests. --- test/libsolidity/SolidityScanner.cpp | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp index e216ef01b..4ccc67885 100644 --- a/test/libsolidity/SolidityScanner.cpp +++ b/test/libsolidity/SolidityScanner.cpp @@ -23,6 +23,8 @@ #include #include +using namespace std; + namespace dev { namespace solidity @@ -401,6 +403,102 @@ BOOST_AUTO_TEST_CASE(invalid_multiline_comment_close) BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); } +BOOST_AUTO_TEST_CASE(multiline_doc_comment_at_eos) +{ + // This used to parse as "whitespace" + Scanner scanner(CharStream("/**")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + +BOOST_AUTO_TEST_CASE(multiline_comment_at_eos) +{ + Scanner scanner(CharStream("/*")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + +BOOST_AUTO_TEST_CASE(regular_line_break_in_single_line_comment) +{ + for (auto const& nl: {"\r", "\n"}) + { + Scanner scanner(CharStream("// abc " + string(nl) + " def ")); + BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), ""); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} + +BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_single_line_comment) +{ + for (auto const& nl: {"\v", "\f", "\xE2\x80\xA8", "\xE2\x80\xA9"}) + { + Scanner scanner(CharStream("// abc " + string(nl) + " def ")); + BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), ""); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + for (size_t i = 0; i < string(nl).size() - 1; i++) + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} + +BOOST_AUTO_TEST_CASE(regular_line_breaks_in_single_line_doc_comment) +{ + for (auto const& nl: {"\r", "\n"}) + { + Scanner scanner(CharStream("/// abc " + string(nl) + " def ")); + BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "abc "); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} + +BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_single_line_doc_comment) +{ + for (auto const& nl: {"\v", "\f", "\xE2\x80\xA8", "\xE2\x80\xA9"}) + { + Scanner scanner(CharStream("/// abc " + string(nl) + " def ")); + BOOST_CHECK_EQUAL(scanner.currentCommentLiteral(), "abc "); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + for (size_t i = 0; i < string(nl).size() - 1; i++) + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} + +BOOST_AUTO_TEST_CASE(regular_line_breaks_in_strings) +{ + for (auto const& nl: {"\n", "\r"}) + { + Scanner scanner(CharStream("\"abc " + string(nl) + " def\"")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} + +BOOST_AUTO_TEST_CASE(irregular_line_breaks_in_strings) +{ + for (auto const& nl: {"\v", "\f", "\xE2\x80\xA8", "\xE2\x80\xA9"}) + { + Scanner scanner(CharStream("\"abc " + string(nl) + " def\"")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal); + for (size_t i = 0; i < string(nl).size(); i++) + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "def"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); + } +} BOOST_AUTO_TEST_SUITE_END() From 55e4532c7231ea7f4ab54402ebac84406564b64b Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 16:44:59 +0200 Subject: [PATCH 12/25] Changelog. --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 26f7d5e20..1a02ade5f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,9 @@ Bugfixes: * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values. + * Parser: Treat unicode line endings as terminating strings and single-line comments. + * Parser: Disallow unterminated multi-line comments at the end of input. + * Parser: Treat ``/** /`` as unterminated multi-line comment. ### 0.4.24 (2018-05-16) From f190caf538f25baa200195baf6f7444927faf926 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Sep 2018 16:51:17 +0200 Subject: [PATCH 13/25] Tests. --- test/libsolidity/SolidityEndToEndTest.cpp | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index a4b597616..f2cc78bfa 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -10743,6 +10743,46 @@ BOOST_AUTO_TEST_CASE(shift_bytes_cleanup) ABI_CHECK(callContractFunction("right(uint8)", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); } +BOOST_AUTO_TEST_CASE(exp_cleanup) +{ + char const* sourceCode = R"( + contract C { + function f() public pure returns (uint8 x) { + uint8 y = uint8(2) ** uint8(8); + return 0 ** y; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); +} + +BOOST_AUTO_TEST_CASE(exp_cleanup_direct) +{ + char const* sourceCode = R"( + contract C { + function f() public pure returns (uint8 x) { + return uint8(0) ** uint8(uint8(2) ** uint8(8)); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); +} + +BOOST_AUTO_TEST_CASE(exp_cleanup_nonzero_base) +{ + char const* sourceCode = R"( + contract C { + function f() public pure returns (uint8 x) { + return uint8(0x166) ** uint8(uint8(2) ** uint8(8)); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); +} + BOOST_AUTO_TEST_CASE(cleanup_in_compound_assign) { char const* sourceCode = R"( From eb7978d6314b51b3b00dbc6155cedd799a5cd767 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Sep 2018 16:51:22 +0200 Subject: [PATCH 14/25] Always perform cleanup for EXP. --- libsolidity/codegen/ExpressionCompiler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4bcc1fa91..f38c1e674 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2069,7 +2069,9 @@ bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _ { if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) return true; - else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod)) + else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod || _op == Token::Exp)) + // We need cleanup for EXP because 0**0 == 1, but 0**0x100 == 0 + // It would suffice to clean the exponent, though. return true; else return false; From be713ed1176c4dee2c1e444d41e5a72ab9caf115 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Sep 2018 16:55:45 +0200 Subject: [PATCH 15/25] Changelog entry and bug list. --- Changelog.md | 3 ++- docs/bugs.json | 7 +++++ docs/bugs_by_version.json | 55 ++++++++++++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/Changelog.md b/Changelog.md index 2a04c8a1a..05e0e5ebe 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.4.25 (unreleased) -Bugfixes: +Important Bugfixes: + * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types. * 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. * Parser: Treat unicode line endings as terminating strings and single-line comments. diff --git a/docs/bugs.json b/docs/bugs.json index 423c314d5..d0704c1f9 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -7,6 +7,13 @@ "fixed": "0.4.25", "severity": "very low" }, + { + "name": "ExpCleanupZero", + "summary": "Using exponentiating with types shorter than 256 bits and zero as base can result in unexpected values.", + "description": "As defined by the EVM, 0 ** 0 is one. Solidity does not always remove dirty higher order bits of types that are smaller than 256 bits before applying an operation because it does not matter if the cleanup is performed before or after the operation. This is true for EXP except for the case where the base is zero, which was overlooked.", + "fixed": "0.4.25", + "severity": "high" + }, { "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.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 00531b9e2..5bd434155 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1,6 +1,7 @@ { "0.1.0": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -18,6 +19,7 @@ }, "0.1.1": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -35,6 +37,7 @@ }, "0.1.2": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -52,6 +55,7 @@ }, "0.1.3": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -69,6 +73,7 @@ }, "0.1.4": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -86,6 +91,7 @@ }, "0.1.5": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -103,6 +109,7 @@ }, "0.1.6": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -121,6 +128,7 @@ }, "0.1.7": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -139,6 +147,7 @@ }, "0.2.0": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -157,6 +166,7 @@ }, "0.2.1": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -175,6 +185,7 @@ }, "0.2.2": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -193,6 +204,7 @@ }, "0.3.0": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -211,6 +223,7 @@ }, "0.3.1": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -228,6 +241,7 @@ }, "0.3.2": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -245,6 +259,7 @@ }, "0.3.3": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -261,6 +276,7 @@ }, "0.3.4": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -277,6 +293,7 @@ }, "0.3.5": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -293,6 +310,7 @@ }, "0.3.6": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -307,6 +325,7 @@ }, "0.4.0": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -321,6 +340,7 @@ }, "0.4.1": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -335,6 +355,7 @@ }, "0.4.10": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -345,6 +366,7 @@ }, "0.4.11": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -354,6 +376,7 @@ }, "0.4.12": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -362,6 +385,7 @@ }, "0.4.13": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -370,6 +394,7 @@ }, "0.4.14": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue" ], @@ -377,12 +402,14 @@ }, "0.4.15": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector" ], "released": "2017-08-08" }, "0.4.16": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector" ], "released": "2017-08-24" @@ -390,24 +417,28 @@ "0.4.17": { "bugs": [ "EventStructWrongData", + "ExpCleanupZero", "ZeroFunctionSelector" ], "released": "2017-09-21" }, "0.4.18": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2017-10-18" }, "0.4.19": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2017-11-30" }, "0.4.2": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -421,37 +452,43 @@ }, "0.4.20": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2018-02-14" }, "0.4.21": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2018-03-07" }, "0.4.22": { "bugs": [ "EventStructWrongData", + "ExpCleanupZero", "OneOfTwoConstructorsSkipped" ], "released": "2018-04-16" }, "0.4.23": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2018-04-19" }, "0.4.24": { "bugs": [ - "EventStructWrongData" + "EventStructWrongData", + "ExpCleanupZero" ], "released": "2018-05-16" }, "0.4.3": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -464,6 +501,7 @@ }, "0.4.4": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -475,6 +513,7 @@ }, "0.4.5": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -487,6 +526,7 @@ }, "0.4.6": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -498,6 +538,7 @@ }, "0.4.7": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -508,6 +549,7 @@ }, "0.4.8": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -518,6 +560,7 @@ }, "0.4.9": { "bugs": [ + "ExpCleanupZero", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", From 3b7be594cf046cc34864cefbd3cf0f5159770163 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 6 Sep 2018 17:30:51 +0200 Subject: [PATCH 16/25] Update bug description, add regex and tests. --- docs/bugs.json | 9 ++- docs/bugs_by_version.json | 86 ++++++++++---------- test/buglist_test_vectors.md | 148 +++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 47 deletions(-) create mode 100644 test/buglist_test_vectors.md diff --git a/docs/bugs.json b/docs/bugs.json index d0704c1f9..560176d12 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -8,11 +8,12 @@ "severity": "very low" }, { - "name": "ExpCleanupZero", - "summary": "Using exponentiating with types shorter than 256 bits and zero as base can result in unexpected values.", - "description": "As defined by the EVM, 0 ** 0 is one. Solidity does not always remove dirty higher order bits of types that are smaller than 256 bits before applying an operation because it does not matter if the cleanup is performed before or after the operation. This is true for EXP except for the case where the base is zero, which was overlooked.", + "name": "ExpExponentCleanup", + "summary": "Using the ** operator with an exponent of type shorter than 256 bits can result in unexpected values.", + "description": "Higher order bits in the exponent are not properly cleaned before the EXP opcode is applied if the type of the exponent expression is smaller than 256 bits and not smaller than the type of the base. In that case, the result might be larger than expected if the exponent is assumed to lie within the value range of the type. Literal numbers as exponents are unaffected as are exponents or bases of type uint256.", "fixed": "0.4.25", - "severity": "high" + "severity": "medium/high", + "check": {"regex-source": "[^/]\\*\\* *[^/0-9 ]"} }, { "name": "OneOfTwoConstructorsSkipped", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 5bd434155..d678bf21d 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1,7 +1,7 @@ { "0.1.0": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -19,7 +19,7 @@ }, "0.1.1": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -37,7 +37,7 @@ }, "0.1.2": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -55,7 +55,7 @@ }, "0.1.3": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -73,7 +73,7 @@ }, "0.1.4": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -91,7 +91,7 @@ }, "0.1.5": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -109,7 +109,7 @@ }, "0.1.6": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -128,7 +128,7 @@ }, "0.1.7": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -147,7 +147,7 @@ }, "0.2.0": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -166,7 +166,7 @@ }, "0.2.1": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -185,7 +185,7 @@ }, "0.2.2": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -204,7 +204,7 @@ }, "0.3.0": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -223,7 +223,7 @@ }, "0.3.1": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -241,7 +241,7 @@ }, "0.3.2": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -259,7 +259,7 @@ }, "0.3.3": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -276,7 +276,7 @@ }, "0.3.4": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -293,7 +293,7 @@ }, "0.3.5": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -310,7 +310,7 @@ }, "0.3.6": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -325,7 +325,7 @@ }, "0.4.0": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -340,7 +340,7 @@ }, "0.4.1": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -355,7 +355,7 @@ }, "0.4.10": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -366,7 +366,7 @@ }, "0.4.11": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -376,7 +376,7 @@ }, "0.4.12": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -385,7 +385,7 @@ }, "0.4.13": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -394,7 +394,7 @@ }, "0.4.14": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue" ], @@ -402,14 +402,14 @@ }, "0.4.15": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector" ], "released": "2017-08-08" }, "0.4.16": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector" ], "released": "2017-08-24" @@ -417,7 +417,7 @@ "0.4.17": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector" ], "released": "2017-09-21" @@ -425,20 +425,20 @@ "0.4.18": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2017-10-18" }, "0.4.19": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2017-11-30" }, "0.4.2": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -453,21 +453,21 @@ "0.4.20": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2018-02-14" }, "0.4.21": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2018-03-07" }, "0.4.22": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero", + "ExpExponentCleanup", "OneOfTwoConstructorsSkipped" ], "released": "2018-04-16" @@ -475,20 +475,20 @@ "0.4.23": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2018-04-19" }, "0.4.24": { "bugs": [ "EventStructWrongData", - "ExpCleanupZero" + "ExpExponentCleanup" ], "released": "2018-05-16" }, "0.4.3": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -501,7 +501,7 @@ }, "0.4.4": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -513,7 +513,7 @@ }, "0.4.5": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -526,7 +526,7 @@ }, "0.4.6": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -538,7 +538,7 @@ }, "0.4.7": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -549,7 +549,7 @@ }, "0.4.8": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -560,7 +560,7 @@ }, "0.4.9": { "bugs": [ - "ExpCleanupZero", + "ExpExponentCleanup", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", diff --git a/test/buglist_test_vectors.md b/test/buglist_test_vectors.md new file mode 100644 index 000000000..e683f4818 --- /dev/null +++ b/test/buglist_test_vectors.md @@ -0,0 +1,148 @@ +# NestedArrayFunctionCallDecoder + +## buggy + +function f() pure returns (uint[2][2]) { } + +-- + +function f() returns (uint[2][2] a) { } + +-- + +function f() returns (uint x, uint[200][2] a) { } + +-- + +function f() returns (uint[200][2] a, uint x) { } + +-- + +function f() returns (uint[200][2] a, uint x); + +-- + +function f() returns ( + uint + [ + 200 + ] + [2] + a, uint x); + +-- + +function f() returns ( + uint + [ + ContractName.ConstantName + ] + [2] + a, uint x); + +## fine + +function f() returns (uint[2]) { } + +-- + +function f() public pure returns (uint[2][] a) { } + +-- + +function f() public pure returns (uint[ 2 ] [ ] a) { } + +-- + +function f() public pure returns (uint x, uint[] a) { } + +-- + +function f(uint[2][2]) { } + +-- + +function f() m(uint[2][2]) { } + +-- + +function f() returns (uint, uint) { uint[2][2] memory x; } + +# ExpExponentCleanup + +## buggy + +x ** y + +-- + +x ** uint8(y) + +-- + +x**y + +## fine + +x ** 2 + +-- + +x**2 + +-- + +x**200 + +-- + +/** bla **/ + +-- + +/**/ + +# EventStructWrongData + +## buggy + +pragma experimental ABIEncoderV2; +contract C +{ + struct S { uint x; } + event E(S); + event F(S); + enum A { B, C } + event G(A); + function f(S s); +} + +-- + +pragma experimental ABIEncoderV2; +contract C +{ + struct S { uint x; } + event E(S indexed); + event F(uint, S, bool); +} + +## fine + +pragma experimental ABIEncoderV2; +contract C +{ + struct S { uint x; } + enum A { B, C } + event G(A); +} + +-- + +pragma experimental ABIEncoderV2; +contract C +{ + struct S { uint x; } + function f(S s); + S s1; +} From 69320472afe8c1c5031c3243ef6299cbfcd2e523 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 21 Aug 2018 16:09:53 +0200 Subject: [PATCH 17/25] Buglist check script supports json paths --- circle.yml | 17 +++++ docs/bugs.json | 26 +++++--- docs/bugs.rst | 13 ++++ docs/bugs_by_version.json | 56 +++++++++++++--- test/buglistTests.js | 134 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 228 insertions(+), 18 deletions(-) create mode 100755 test/buglistTests.js diff --git a/circle.yml b/circle.yml index 4ce3082bf..fb504ba14 100644 --- a/circle.yml +++ b/circle.yml @@ -155,6 +155,23 @@ jobs: - store_artifacts: *solc_artifact - persist_to_workspace: *all_artifacts + test_buglist: + docker: + - image: circleci/node + environment: + TERM: xterm + steps: + - checkout + - run: + name: JS deps + command: | + npm install download + npm install JSONPath + npm install mktemp + - run: + name: Test buglist + command: ./test/buglistTests.js + test_x86_linux: docker: - image: buildpack-deps:artful diff --git a/docs/bugs.json b/docs/bugs.json index 560176d12..28c0fe623 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,12 +1,4 @@ [ - { - "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": "ExpExponentCleanup", "summary": "Using the ** operator with an exponent of type shorter than 256 bits can result in unexpected values.", @@ -15,6 +7,24 @@ "severity": "medium/high", "check": {"regex-source": "[^/]\\*\\* *[^/0-9 ]"} }, + { + "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", + "check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"} + }, + { + "name": "NestedArrayFunctionCallDecoder", + "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.", + "description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.", + "introduced": "0.1.4", + "fixed": "0.4.22", + "severity": "medium", + "check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"} + }, { "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.", diff --git a/docs/bugs.rst b/docs/bugs.rst index 7629830df..f7522183a 100644 --- a/docs/bugs.rst +++ b/docs/bugs.rst @@ -56,6 +56,19 @@ conditions is an object that can contain a boolean value ``optimizer``, which means that the optimizer has to be switched on to enable the bug. If no conditions are given, assume that the bug is present. +check + This field contains different checks that report whether the smart contract + contains the bug or not. The first type of check are Javascript regular + expressions that are to be matched against the source code ("source-regex") + if the bug is present. If there is no match, then the bug is very likely + not present. If there is a match, the bug might be present. For improved + accuracy, the checks should be applied to the source code after stripping + comments. + The second type of check are patterns to be checked on the compact AST of + the Solidity program ("ast-compact-json-path"). The specified search query + is a `JsonPath `_ expression. + If at least one path of the Solidity AST matches the query, the bug is + likely present. .. literalinclude:: bugs.json :language: js diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index d678bf21d..88a480b2c 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -74,6 +74,7 @@ "0.1.4": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -92,6 +93,7 @@ "0.1.5": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -110,6 +112,7 @@ "0.1.6": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -129,6 +132,7 @@ "0.1.7": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -148,6 +152,7 @@ "0.2.0": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -167,6 +172,7 @@ "0.2.1": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -186,6 +192,7 @@ "0.2.2": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "ECRecoverMalformedInput", "SkipEmptyStringLiteral", @@ -205,6 +212,7 @@ "0.3.0": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -224,6 +232,7 @@ "0.3.1": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -242,6 +251,7 @@ "0.3.2": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -260,6 +270,7 @@ "0.3.3": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -277,6 +288,7 @@ "0.3.4": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -294,6 +306,7 @@ "0.3.5": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -311,6 +324,7 @@ "0.3.6": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -326,6 +340,7 @@ "0.4.0": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -341,6 +356,7 @@ "0.4.1": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -356,6 +372,7 @@ "0.4.10": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -367,6 +384,7 @@ "0.4.11": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -377,6 +395,7 @@ "0.4.12": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -386,6 +405,7 @@ "0.4.13": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -395,6 +415,7 @@ "0.4.14": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue" ], @@ -403,6 +424,7 @@ "0.4.15": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-08-08" @@ -410,35 +432,40 @@ "0.4.16": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-08-24" }, "0.4.17": { "bugs": [ - "EventStructWrongData", "ExpExponentCleanup", + "EventStructWrongData", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-09-21" }, "0.4.18": { "bugs": [ + "ExpExponentCleanup", "EventStructWrongData", - "ExpExponentCleanup" + "NestedArrayFunctionCallDecoder" ], "released": "2017-10-18" }, "0.4.19": { "bugs": [ + "ExpExponentCleanup", "EventStructWrongData", - "ExpExponentCleanup" + "NestedArrayFunctionCallDecoder" ], "released": "2017-11-30" }, "0.4.2": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -452,43 +479,46 @@ }, "0.4.20": { "bugs": [ + "ExpExponentCleanup", "EventStructWrongData", - "ExpExponentCleanup" + "NestedArrayFunctionCallDecoder" ], "released": "2018-02-14" }, "0.4.21": { "bugs": [ + "ExpExponentCleanup", "EventStructWrongData", - "ExpExponentCleanup" + "NestedArrayFunctionCallDecoder" ], "released": "2018-03-07" }, "0.4.22": { "bugs": [ - "EventStructWrongData", "ExpExponentCleanup", + "EventStructWrongData", "OneOfTwoConstructorsSkipped" ], "released": "2018-04-16" }, "0.4.23": { "bugs": [ - "EventStructWrongData", - "ExpExponentCleanup" + "ExpExponentCleanup", + "EventStructWrongData" ], "released": "2018-04-19" }, "0.4.24": { "bugs": [ - "EventStructWrongData", - "ExpExponentCleanup" + "ExpExponentCleanup", + "EventStructWrongData" ], "released": "2018-05-16" }, "0.4.3": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -502,6 +532,7 @@ "0.4.4": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -514,6 +545,7 @@ "0.4.5": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -527,6 +559,7 @@ "0.4.6": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -539,6 +572,7 @@ "0.4.7": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -550,6 +584,7 @@ "0.4.8": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -561,6 +596,7 @@ "0.4.9": { "bugs": [ "ExpExponentCleanup", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", diff --git a/test/buglistTests.js b/test/buglistTests.js new file mode 100755 index 000000000..f24f0cb68 --- /dev/null +++ b/test/buglistTests.js @@ -0,0 +1,134 @@ +#!/usr/bin/env node + +"use strict"; + +var util = require('util') +var exec = util.promisify(require('child_process').exec) +var mktemp = require('mktemp'); +var download = require('download') +var JSONPath = require('JSONPath') +var fs = require('fs') +var bugs = JSON.parse(fs.readFileSync(__dirname + '/../docs/bugs.json', 'utf8')) + +var bugsByName = {} +for (var i in bugs) +{ + if (bugs[i].name in bugsByName) + { + throw "Duplicate bug name: " + bugs[i].name + } + bugsByName[bugs[i].name] = bugs[i] +} + +var tests = fs.readFileSync(__dirname + '/buglist_test_vectors.md', 'utf8') + +var testVectorParser = /\s*#\s+(\S+)\s+## buggy\n([^#]*)## fine\n([^#]*)/g + +runTests() + +async function runTests() +{ + var result; + while ((result = testVectorParser.exec(tests)) !== null) + { + var name = result[1] + var buggy = result[2].split('\n--\n') + var fine = result[3].split('\n--\n') + console.log("Testing " + name + " with " + buggy.length + " buggy and " + fine.length + " fine instances") + + try { + await checkRegex(name, buggy, fine) + await checkJSONPath(name, buggy, fine) + } catch (err) { + console.error("Error: " + err) + } + } +} + +function checkRegex(name, buggy, fine) +{ + return new Promise(function(resolve, reject) { + var regexStr = bugsByName[name].check['regex-source'] + if (regexStr !== undefined) + { + var regex = RegExp(regexStr) + for (var i in buggy) + { + if (!regex.exec(buggy[i])) + { + reject("Bug " + name + ": Buggy source does not match: " + buggy[i]) + } + } + for (var i in fine) + { + if (regex.exec(fine[i])) + { + reject("Bug " + name + ": Non-buggy source matches: " + fine[i]) + } + } + } + resolve() + }) +} + +async function checkJSONPath(name, buggy, fine) +{ + var jsonPath = bugsByName[name].check['ast-compact-json-path'] + if (jsonPath !== undefined) + { + var url = "http://github.com/ethereum/solidity/releases/download/v" + bugsByName[name].introduced + "/solc-static-linux" + try { + var tmpdir = await mktemp.createDir('XXXXX') + var binary = tmpdir + "/solc-static-linux" + await download(url, tmpdir) + exec("chmod +x " + binary) + for (var i in buggy) + { + var result = await checkJsonPathTest(buggy[i], tmpdir, binary, jsonPath, i) + if (!result) + throw "Bug " + name + ": Buggy source does not contain path: " + buggy[i] + } + for (var i in fine) + { + var result = await checkJsonPathTest(fine[i], tmpdir, binary, jsonPath, i + buggy.length) + if (result) + throw "Bug " + name + ": Non-buggy source contains path: " + fine[i] + } + exec("rm -r " + tmpdir) + } catch (err) { + throw err + } + } +} + +function checkJsonPathTest(code, tmpdir, binary, query, idx) { + return new Promise(function(resolve, reject) { + var solFile = tmpdir + "/jsonPath" + idx + ".sol" + var astFile = tmpdir + "/ast" + idx + ".json" + writeFilePromise(solFile, code) + .then(() => { + return exec(binary + " --ast-compact-json " + solFile + " > " + astFile) + }) + .then(() => { + var jsonRE = /(\{[\s\S]*\})/ + var ast = JSON.parse(jsonRE.exec(fs.readFileSync(astFile, 'utf8'))[0]) + var result = JSONPath({json: ast, path: query}) + if (result.length > 0) + resolve(true) + else + resolve(false) + }) + .catch((err) => { + reject(err) + }) + }) +} + +function writeFilePromise(filename, data) { + return new Promise(function(resolve, reject) { + fs.writeFile(filename, data, 'utf8', function(err) { + if (err) reject(err) + else resolve(data) + }) + }) +} From 75e38be05035ecbcb7c77bde53dbc6cbc22e88d4 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 25 Jul 2018 15:53:03 +0200 Subject: [PATCH 18/25] Bugfix entry regarding nested arrays returned by library functions --- circle.yml | 1 + docs/bugs.json | 20 ++++++++++++++------ docs/bugs.rst | 9 +++++---- docs/bugs_by_version.json | 11 +++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/circle.yml b/circle.yml index fb504ba14..7c95fa7ff 100644 --- a/circle.yml +++ b/circle.yml @@ -234,6 +234,7 @@ workflows: version: 2 build_all: jobs: + - test_buglist: *build_on_tags - build_emscripten: *build_on_tags - test_emscripten_solcjs: <<: *build_on_tags diff --git a/docs/bugs.json b/docs/bugs.json index 28c0fe623..c1e377a41 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -17,13 +17,12 @@ "check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"} }, { - "name": "NestedArrayFunctionCallDecoder", - "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.", - "description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.", - "introduced": "0.1.4", + "name": "PublicLibFunctionsDoNotReturnNestedArrays", + "summary": "Calls to public library functions (internal functions are safe) that return nested arrays return only zeroes.", + "description": "The compiler does not complain about public library functions (internal functions are safe) returning nested arrays, but it also does not return it correctly. Thus, the function caller receives only zeroes.", + "introduced": "0.4.11", "fixed": "0.4.22", - "severity": "medium", - "check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"} + "severity": "low" }, { "name": "OneOfTwoConstructorsSkipped", @@ -33,6 +32,15 @@ "fixed": "0.4.23", "severity": "very low" }, + { + "name": "NestedArrayFunctionCallDecoder", + "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.", + "description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.", + "introduced": "0.1.4", + "fixed": "0.4.22", + "severity": "medium", + "check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"} + }, { "name": "ZeroFunctionSelector", "summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.", diff --git a/docs/bugs.rst b/docs/bugs.rst index f7522183a..8e3382c86 100644 --- a/docs/bugs.rst +++ b/docs/bugs.rst @@ -57,14 +57,15 @@ conditions means that the optimizer has to be switched on to enable the bug. If no conditions are given, assume that the bug is present. check - This field contains different checks that report whether the smart contract + This field contains different checks that can be used to determine + whether a smart contract contains the bug or not. The first type of check are Javascript regular - expressions that are to be matched against the source code ("source-regex") - if the bug is present. If there is no match, then the bug is very likely + expressions that are to be matched against the source code ("source-regex"). + If there is no match, then the bug is very likely not present. If there is a match, the bug might be present. For improved accuracy, the checks should be applied to the source code after stripping comments. - The second type of check are patterns to be checked on the compact AST of + The second type of check are patterns to be applied to the compact AST of the Solidity program ("ast-compact-json-path"). The specified search query is a `JsonPath `_ expression. If at least one path of the Solidity AST matches the query, the bug is diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 88a480b2c..90879db97 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -384,6 +384,7 @@ "0.4.11": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", @@ -395,6 +396,7 @@ "0.4.12": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", @@ -405,6 +407,7 @@ "0.4.13": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", @@ -415,6 +418,7 @@ "0.4.14": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue" @@ -424,6 +428,7 @@ "0.4.15": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], @@ -432,6 +437,7 @@ "0.4.16": { "bugs": [ "ExpExponentCleanup", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], @@ -441,6 +447,7 @@ "bugs": [ "ExpExponentCleanup", "EventStructWrongData", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], @@ -450,6 +457,7 @@ "bugs": [ "ExpExponentCleanup", "EventStructWrongData", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder" ], "released": "2017-10-18" @@ -458,6 +466,7 @@ "bugs": [ "ExpExponentCleanup", "EventStructWrongData", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder" ], "released": "2017-11-30" @@ -481,6 +490,7 @@ "bugs": [ "ExpExponentCleanup", "EventStructWrongData", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder" ], "released": "2018-02-14" @@ -489,6 +499,7 @@ "bugs": [ "ExpExponentCleanup", "EventStructWrongData", + "PublicLibFunctionsDoNotReturnNestedArrays", "NestedArrayFunctionCallDecoder" ], "released": "2018-03-07" From 8c56a5912b49000fbb66bdb8c5ad63131bfa9f30 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 12 Sep 2018 18:38:16 +0200 Subject: [PATCH 19/25] Set relase date of 0.4.25. --- Changelog.md | 2 +- docs/bugs_by_version.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 05e0e5ebe..29c28e301 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -### 0.4.25 (unreleased) +### 0.4.25 (2018-09-12) Important Bugfixes: * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types. diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 90879db97..ef0846606 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -526,6 +526,10 @@ ], "released": "2018-05-16" }, + "0.4.25": { + "bugs": [], + "released": "2018-09-12" + }, "0.4.3": { "bugs": [ "ExpExponentCleanup", From 73973d2448fd0965b3aa988d18397e9dce6d949d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 17 May 2018 14:42:22 +0200 Subject: [PATCH 20/25] CMake: Fix libdir for jsoncpp external project in special case When building on Debian/Ubuntu with install prefix /usr (e.g. in PPA builds) the CMAKE_INSTALL_LIBDIR is resolved to lib/x86_64-linux-gnu. For jsoncpp external project this is never the case because the install prefix is not /usr. Remove multiarch part from libdir if there. --- cmake/jsoncpp.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index 3d6b37edf..cc2da7e7e 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -7,8 +7,14 @@ else() endif() include(GNUInstallDirs) +set(libdir ${CMAKE_INSTALL_LIBDIR}) +if(CMAKE_LIBRARY_ARCHITECTURE) + # Do not use Debian multiarch library dir. + string(REPLACE "/${CMAKE_LIBRARY_ARCHITECTURE}" "" libdir ${libdir}) +endif() + set(prefix "${CMAKE_BINARY_DIR}/deps") -set(JSONCPP_LIBRARY "${prefix}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(JSONCPP_LIBRARY "${prefix}/${libdir}/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") set(JSONCPP_INCLUDE_DIR "${prefix}/include") if(NOT MSVC) From 1a5f90954a203db2dab53a569e9e6912457cee96 Mon Sep 17 00:00:00 2001 From: mingchuan Date: Wed, 6 Jun 2018 14:03:07 +0800 Subject: [PATCH 21/25] Fix cmake when custom CMAKE_INSTALL_LIBDIR is given According to cmake documents, we cannot assume CMAKE_INSTALL_LIBDIR is a relative path. This commit fixes the "no rule to make libjsoncpp.a" error by passing -DCMAKE_INSTALL_LIBDIR=lib to jsoncpp external project. --- cmake/jsoncpp.cmake | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index cc2da7e7e..0c110b532 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -6,15 +6,8 @@ else() set(JSONCPP_CMAKE_COMMAND ${CMAKE_COMMAND}) endif() -include(GNUInstallDirs) -set(libdir ${CMAKE_INSTALL_LIBDIR}) -if(CMAKE_LIBRARY_ARCHITECTURE) - # Do not use Debian multiarch library dir. - string(REPLACE "/${CMAKE_LIBRARY_ARCHITECTURE}" "" libdir ${libdir}) -endif() - set(prefix "${CMAKE_BINARY_DIR}/deps") -set(JSONCPP_LIBRARY "${prefix}/${libdir}/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(JSONCPP_LIBRARY "${prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") set(JSONCPP_INCLUDE_DIR "${prefix}/include") if(NOT MSVC) @@ -36,6 +29,7 @@ ExternalProject_Add(jsoncpp-project CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_INSTALL_LIBDIR=lib # Build static lib but suitable to be included in a shared lib. -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS} -DJSONCPP_WITH_TESTS=OFF From 72b9ad6837b6d080e1646dbbd58219630fbf0021 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Tue, 10 Jul 2018 15:12:32 +0200 Subject: [PATCH 22/25] Visual Studio 2017 build-time (linking) fix and improvements --- .gitignore | 3 +++ cmake/EthCompilerSettings.cmake | 11 ----------- cmake/jsoncpp.cmake | 4 +--- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 14c227d05..87a3e5933 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ build/ docs/_build docs/utils/__pycache__ docs/utils/*.pyc +/deps/downloads/ # vim stuff *.swp @@ -43,3 +44,5 @@ docs/utils/*.pyc .idea browse.VC.db CMakeLists.txt.user +/CMakeSettings.json +/.vs diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 683d1d2e6..3ae5bf2ab 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -132,17 +132,6 @@ elseif (DEFINED MSVC) add_compile_options(-D_WIN32_WINNT=0x0600) # declare Windows Vista API requirement add_compile_options(-DNOMINMAX) # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions - # Always use Release variant of C++ runtime. - # We don't want to provide Debug variants of all dependencies. Some default - # flags set by CMake must be tweaked. - string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REPLACE "/D_DEBUG" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") - string(REPLACE "/D_DEBUG" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") - string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") - set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS OFF) - # disable empty object file warning set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index 0c110b532..e886c6092 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -35,9 +35,7 @@ ExternalProject_Add(jsoncpp-project -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF -DCMAKE_CXX_FLAGS=${JSONCPP_EXTRA_FLAGS} - # Overwrite build and install commands to force Release build on MSVC. - BUILD_COMMAND cmake --build --config Release - INSTALL_COMMAND cmake --build --config Release --target install + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${byproducts} ) From d2d9162bb95c2d3eb2ae57422b24ca5c3b69a935 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Thu, 19 Jul 2018 00:05:45 +0200 Subject: [PATCH 23/25] Propagate original CMAKE_CXX_FLAGS to jsoncpp compilation --- cmake/jsoncpp.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index e886c6092..a6ca0e7fa 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -34,7 +34,7 @@ ExternalProject_Add(jsoncpp-project -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS} -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF - -DCMAKE_CXX_FLAGS=${JSONCPP_EXTRA_FLAGS} + -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} ${JSONCPP_EXTRA_FLAGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${byproducts} ) From 84d92450767480dcd0748c781e3cbda8e4a82ebd Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Aug 2018 16:50:08 +0200 Subject: [PATCH 24/25] Rename JSONCPP_EXTRA_FLAGS to JSONCPP_CXX_FLAGS, add EMSCRIPTEN workaround and remove obsolete MSVC workaround. --- cmake/jsoncpp.cmake | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index a6ca0e7fa..ea3218efc 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -10,8 +10,16 @@ set(prefix "${CMAKE_BINARY_DIR}/deps") set(JSONCPP_LIBRARY "${prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") set(JSONCPP_INCLUDE_DIR "${prefix}/include") -if(NOT MSVC) - set(JSONCPP_EXTRA_FLAGS "-std=c++11") +# TODO: Investigate why this breaks some emscripten builds and +# check whether this can be removed after updating the emscripten +# versions used in the CI runs. +if(EMSCRIPTEN) + # Do not include all flags in CMAKE_CXX_FLAGS for emscripten, + # but only use -std=c++11. Using all flags causes build failures + # at the moment. + set(JSONCPP_CXX_FLAGS -std=c++11) +else() + set(JSONCPP_CXX_FLAGS ${CMAKE_CXX_FLAGS}) endif() set(byproducts "") @@ -34,7 +42,7 @@ ExternalProject_Add(jsoncpp-project -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS} -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF - -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} ${JSONCPP_EXTRA_FLAGS} + -DCMAKE_CXX_FLAGS=${JSONCPP_CXX_FLAGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${byproducts} ) From 6ed88d1bfe9e92e8b34c4f933467aa4a1f056dd7 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 13 Sep 2018 16:34:22 +0200 Subject: [PATCH 25/25] Update changelog. --- Changelog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 29c28e301..bfe82f8c0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,8 @@ Important Bugfixes: * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types. * 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. - * Parser: Treat unicode line endings as terminating strings and single-line comments. + * Parser: Consider all unicode line terminators (LF, VF, FF, CR, NEL, LS, PS) for single-line comments + and string literals. They are invalid in strings and will end comments. * Parser: Disallow unterminated multi-line comments at the end of input. * Parser: Treat ``/** /`` as unterminated multi-line comment.