mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11888 from ethereum/spdx-license-handling-10145
Properly detect multiple licenses and validate them.
This commit is contained in:
commit
4284499180
@ -22,6 +22,7 @@ Bugfixes:
|
|||||||
* Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes.
|
* 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.
|
* 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.
|
* 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 negative caused by ``push`` on storage array references returned by internal functions.
|
||||||
* SMTChecker: Fix false positive in external calls from constructors.
|
* SMTChecker: Fix false positive in external calls from constructors.
|
||||||
* SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants.
|
* SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants.
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <libyul/backends/evm/EVMDialect.h>
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
#include <boost/algorithm/string/trim.hpp>
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@ -2078,7 +2079,8 @@ bool Parser::variableDeclarationStart()
|
|||||||
optional<string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> const& _nodes)
|
optional<string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> const& _nodes)
|
||||||
{
|
{
|
||||||
// We circumvent the scanner here, because it skips non-docstring comments.
|
// 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.
|
// Search inside all parts of the source not covered by parsed nodes.
|
||||||
// This will leave e.g. "global comments".
|
// This will leave e.g. "global comments".
|
||||||
@ -2093,21 +2095,33 @@ optional<string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> cons
|
|||||||
sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end());
|
sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> matches;
|
vector<string> licenseNames;
|
||||||
for (auto const& [start, end]: sequencesToSearch)
|
for (auto const& [start, end]: sequencesToSearch)
|
||||||
{
|
{
|
||||||
smatch match;
|
auto declarationsBegin = std::sregex_iterator(start, end, licenseDeclarationRegex);
|
||||||
if (regex_search(start, end, match, licenseRegex))
|
auto declarationsEnd = std::sregex_iterator();
|
||||||
|
|
||||||
|
for (std::sregex_iterator declIt = declarationsBegin; declIt != declarationsEnd; ++declIt)
|
||||||
|
if (!declIt->empty())
|
||||||
{
|
{
|
||||||
string license{boost::trim_copy(string(match[1]))};
|
string license = boost::trim_copy(string((*declIt)[1]));
|
||||||
if (!license.empty())
|
licenseNames.emplace_back(std::move(license));
|
||||||
matches.emplace_back(std::move(license));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matches.size() == 1)
|
if (licenseNames.size() == 1)
|
||||||
return matches.front();
|
{
|
||||||
else if (matches.empty())
|
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(
|
parserWarning(
|
||||||
1878_error,
|
1878_error,
|
||||||
{-1, -1, m_scanner->currentLocation().sourceName},
|
{-1, -1, m_scanner->currentLocation().sourceName},
|
||||||
|
@ -120,7 +120,11 @@ done < <(
|
|||||||
# a variable declaration.
|
# a variable declaration.
|
||||||
grep -v -E 'revertStatement/non_called.sol' |
|
grep -v -E 'revertStatement/non_called.sol' |
|
||||||
# Skipping a test with "let basefee := ..."
|
# 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=()
|
YUL_FILES=()
|
||||||
|
@ -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_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)
|
BOOST_AUTO_TEST_CASE(metadata_license_bidi_marks)
|
||||||
{
|
{
|
||||||
char const* sourceCode =
|
char const* sourceCode =
|
||||||
@ -570,15 +548,6 @@ BOOST_AUTO_TEST_CASE(metadata_license_natspec_multiline)
|
|||||||
BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0");
|
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)
|
BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace_multiline)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
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_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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
3
test/libsolidity/syntaxTests/license/license_AND.sol
Normal file
3
test/libsolidity/syntaxTests/license/license_AND.sol
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0 AND GPL-2.0
|
||||||
|
contract C {}
|
||||||
|
// ----
|
3
test/libsolidity/syntaxTests/license/license_OR.sol
Normal file
3
test/libsolidity/syntaxTests/license/license_OR.sol
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0 OR GPL-2.0
|
||||||
|
contract C {}
|
||||||
|
// ----
|
5
test/libsolidity/syntaxTests/license/license_double2.sol
Normal file
5
test/libsolidity/syntaxTests/license/license_double2.sol
Normal file
@ -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.
|
5
test/libsolidity/syntaxTests/license/license_double3.sol
Normal file
5
test/libsolidity/syntaxTests/license/license_double3.sol
Normal file
@ -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.
|
5
test/libsolidity/syntaxTests/license/license_double4.sol
Normal file
5
test/libsolidity/syntaxTests/license/license_double4.sol
Normal file
@ -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.
|
4
test/libsolidity/syntaxTests/license/license_double5.sol
Normal file
4
test/libsolidity/syntaxTests/license/license_double5.sol
Normal file
@ -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.
|
@ -1,4 +1,4 @@
|
|||||||
// This is parsed as GPL-3.0:
|
|
||||||
// SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒
|
// SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒
|
||||||
contract C {}
|
contract C {}
|
||||||
// ----
|
// ----
|
||||||
|
// ParserError 1114: Invalid SPDX license identifier.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒
|
// SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒
|
||||||
contract C {}
|
contract C {}
|
||||||
// ----
|
// ----
|
||||||
// Warning 1878: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" 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.
|
||||||
|
Loading…
Reference in New Issue
Block a user