From c81814915c06f6344b1c68ea00841962f7423612 Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 2 Sep 2021 15:25:10 +0200 Subject: [PATCH] Properly detect multiple licenses and validate them. --- Changelog.md | 1 + libsolidity/parsing/Parser.cpp | 38 ++++++++++++------ scripts/test_antlr_grammar.sh | 6 ++- test/libsolidity/Metadata.cpp | 40 +++++-------------- .../syntaxTests/license/license_AND.sol | 3 ++ .../syntaxTests/license/license_OR.sol | 3 ++ .../syntaxTests/license/license_double2.sol | 5 +++ .../syntaxTests/license/license_double3.sol | 5 +++ .../syntaxTests/license/license_double4.sol | 5 +++ .../syntaxTests/license/license_double5.sol | 4 ++ .../license/license_hidden_unicode.sol | 2 +- .../syntaxTests/license/license_unicode.sol | 2 +- 12 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 test/libsolidity/syntaxTests/license/license_AND.sol create mode 100644 test/libsolidity/syntaxTests/license/license_OR.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double2.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double3.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double4.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double5.sol diff --git a/Changelog.md b/Changelog.md index bd62be0ce..25da9ac42 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,7 @@ Bugfixes: * Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. + * Parser: Properly check for multiple SPDX license identifiers next to each other and validate them. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 3f5c975e3..1d16f7828 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -2078,7 +2079,8 @@ bool Parser::variableDeclarationStart() optional Parser::findLicenseString(std::vector> const& _nodes) { // We circumvent the scanner here, because it skips non-docstring comments. - static regex const licenseRegex("SPDX-License-Identifier:\\s*([a-zA-Z0-9 ()+.-]+)"); + static regex const licenseNameRegex("([a-zA-Z0-9 ()+.-]+)"); + static regex const licenseDeclarationRegex("SPDX-License-Identifier:\\s*(.+?)([\n\r]|(\\*/))"); // Search inside all parts of the source not covered by parsed nodes. // This will leave e.g. "global comments". @@ -2093,21 +2095,33 @@ optional Parser::findLicenseString(std::vector> cons sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end()); } - vector matches; + vector licenseNames; for (auto const& [start, end]: sequencesToSearch) { - smatch match; - if (regex_search(start, end, match, licenseRegex)) - { - string license{boost::trim_copy(string(match[1]))}; - if (!license.empty()) - matches.emplace_back(std::move(license)); - } + auto declarationsBegin = std::sregex_iterator(start, end, licenseDeclarationRegex); + auto declarationsEnd = std::sregex_iterator(); + + for (std::sregex_iterator declIt = declarationsBegin; declIt != declarationsEnd; ++declIt) + if (!declIt->empty()) + { + string license = boost::trim_copy(string((*declIt)[1])); + licenseNames.emplace_back(std::move(license)); + } } - if (matches.size() == 1) - return matches.front(); - else if (matches.empty()) + if (licenseNames.size() == 1) + { + string const& license = licenseNames.front(); + if (regex_match(license, licenseNameRegex)) + return license; + else + parserError( + 1114_error, + {-1, -1, m_scanner->currentLocation().sourceName}, + "Invalid SPDX license identifier." + ); + } + else if (licenseNames.empty()) parserWarning( 1878_error, {-1, -1, m_scanner->currentLocation().sourceName}, diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh index 333cea0df..04c1b08ac 100755 --- a/scripts/test_antlr_grammar.sh +++ b/scripts/test_antlr_grammar.sh @@ -120,7 +120,11 @@ done < <( # a variable declaration. grep -v -E 'revertStatement/non_called.sol' | # Skipping a test with "let basefee := ..." - grep -v -E 'inlineAssembly/basefee_berlin_function.sol' + grep -v -E 'inlineAssembly/basefee_berlin_function.sol' | + # Skipping license error, unrelated to the grammar + grep -v -E 'license/license_double5.sol' | + grep -v -E 'license/license_hidden_unicode.sol' | + grep -v -E 'license/license_unicode.sol' ) YUL_FILES=() diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 8d0b65e4c..d37398637 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -457,28 +457,6 @@ BOOST_AUTO_TEST_CASE(metadata_license_gpl3_or_apache2) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0 OR Apache-2.0"); } -BOOST_AUTO_TEST_CASE(metadata_license_ignored_unicode) -{ - char const* sourceCode = R"( - // SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ - pragma solidity >=0.0; - contract C { - } - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == nullopt); -} - -BOOST_AUTO_TEST_CASE(metadata_license_ignored_stray_unicode) -{ - char const* sourceCode = R"( - // SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ - pragma solidity >=0.0; - contract C { - } - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); -} - BOOST_AUTO_TEST_CASE(metadata_license_bidi_marks) { char const* sourceCode = @@ -570,15 +548,6 @@ BOOST_AUTO_TEST_CASE(metadata_license_natspec_multiline) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); } -BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace) -{ - char const* sourceCode = R"( - //SPDX-License-Identifier:GPL-3.0 - contract C {} - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); -} - BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace_multiline) { char const* sourceCode = R"( @@ -597,6 +566,15 @@ BOOST_AUTO_TEST_CASE(metadata_license_nonempty_line) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); } +BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace) +{ + char const* sourceCode = R"( + //SPDX-License-Identifier:GPL-3.0 + contract C {} + )"; + BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/syntaxTests/license/license_AND.sol b/test/libsolidity/syntaxTests/license/license_AND.sol new file mode 100644 index 000000000..eb996a948 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_AND.sol @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 AND GPL-2.0 +contract C {} +// ---- diff --git a/test/libsolidity/syntaxTests/license/license_OR.sol b/test/libsolidity/syntaxTests/license/license_OR.sol new file mode 100644 index 000000000..9f36bb416 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_OR.sol @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 +contract C {} +// ---- diff --git a/test/libsolidity/syntaxTests/license/license_double2.sol b/test/libsolidity/syntaxTests/license/license_double2.sol new file mode 100644 index 000000000..4c390a3d4 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double2.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: MIT +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double3.sol b/test/libsolidity/syntaxTests/license/license_double3.sol new file mode 100644 index 000000000..10ade5d9d --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double3.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: GPL-3.0 +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double4.sol b/test/libsolidity/syntaxTests/license/license_double4.sol new file mode 100644 index 000000000..395a458ee --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double4.sol @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 +SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double5.sol b/test/libsolidity/syntaxTests/license/license_double5.sol new file mode 100644 index 000000000..efc22186b --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double5.sol @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ /* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol b/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol index 5ce155f32..f93ef18c4 100644 --- a/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol +++ b/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol @@ -1,4 +1,4 @@ -// This is parsed as GPL-3.0: // SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ contract C {} // ---- +// ParserError 1114: Invalid SPDX license identifier. diff --git a/test/libsolidity/syntaxTests/license/license_unicode.sol b/test/libsolidity/syntaxTests/license/license_unicode.sol index 801c6e576..bcf2cdb77 100644 --- a/test/libsolidity/syntaxTests/license/license_unicode.sol +++ b/test/libsolidity/syntaxTests/license/license_unicode.sol @@ -1,4 +1,4 @@ // SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ contract C {} // ---- -// Warning 1878: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +// ParserError 1114: Invalid SPDX license identifier.