diff options
author | chriseth <chris@ethereum.org> | 2018-08-13 19:37:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-13 19:37:04 +0800 |
commit | a2c754b3fed422b3d8027a5298624bcfed3744a5 (patch) | |
tree | 9306c07b3445117a318f14dcde5efd1bd7dcaf9d | |
parent | 43db88b8363d73ee2f5ffa094ff506414261bd11 (diff) | |
parent | a7885e0b0a8808e9daa7cc3b86781997c614b8d3 (diff) | |
download | dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar.gz dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar.bz2 dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar.lz dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar.xz dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.tar.zst dexon-solidity-a2c754b3fed422b3d8027a5298624bcfed3744a5.zip |
Merge pull request #4793 from ethereum/emptyRemappings
Disallow remappings with empty prefix.
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | docs/layout-of-source-files.rst | 11 | ||||
-rw-r--r-- | docs/using-the-compiler.rst | 11 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 37 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 21 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 9 | ||||
-rw-r--r-- | solc/CommandLineInterface.cpp | 15 | ||||
-rw-r--r-- | solc/CommandLineInterface.h | 2 | ||||
-rwxr-xr-x | test/cmdlineTests.sh | 4 | ||||
-rw-r--r-- | test/libsolidity/Imports.cpp | 14 |
10 files changed, 82 insertions, 43 deletions
diff --git a/Changelog.md b/Changelog.md index b2f9bf05..56e00003 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,7 @@ Breaking Changes: * Commandline interface: Remove obsolete ``--formal`` option. * Commandline interface: Rename the ``--julia`` option to ``--yul``. * Commandline interface: Require ``-`` if standard input is used as source. + * Compiler interface: Disallow remappings with empty prefix. * Control Flow Analyzer: Turn warning about returning uninitialized storage pointers into an error. * General: ``continue`` in a ``do...while`` loop jumps to the condition (it used to jump to the loop body). Warning: this may silently change the semantics of existing code. * General: Disallow declaring empty structs. diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 46ef3d57..4bacd704 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -100,11 +100,10 @@ When the compiler is invoked, it is not only possible to specify how to discover the first element of a path, but it is possible to specify path prefix remappings so that e.g. ``github.com/ethereum/dapp-bin/library`` is remapped to ``/usr/local/dapp-bin/library`` and the compiler will read the files from there. -If multiple remappings can be applied, the one with the longest key is tried first. This -allows for a "fallback-remapping" with e.g. ``""`` maps to -``"/usr/local/include/solidity"``. Furthermore, these remappings can -depend on the context, which allows you to configure packages to -import e.g. different versions of a library of the same name. +If multiple remappings can be applied, the one with the longest key is tried first. +An empty prefix is not allowed. Furthermore, these remappings can depend on the context, +which allows you to configure packages to import e.g. different versions of a library +of the same name. **solc**: @@ -148,7 +147,7 @@ Note that solc only allows you to include files from certain directories: They have to be in the directory (or subdirectory) of one of the explicitly specified source files or in the directory (or subdirectory) of a remapping target. If you want to allow direct absolute includes, just add the -remapping ``=/``. +remapping ``/=/``. If there are multiple remappings that lead to a valid file, the remapping with the longest common prefix is chosen. diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 1d7cb97b..b286e1a3 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -23,14 +23,15 @@ it is also possible to provide path redirects using ``prefix=path`` in the follo :: - solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ =/usr/local/lib/fallback file.sol + solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ file.sol This essentially instructs the compiler to search for anything starting with -``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin`` and if it does not -find the file there, it will look at ``/usr/local/lib/fallback`` (the empty prefix -always matches). ``solc`` will not read files from the filesystem that lie outside of +``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin``. +``solc`` will not read files from the filesystem that lie outside of the remapping targets and outside of the directories where explicitly specified source -files reside, so things like ``import "/etc/passwd";`` only work if you add ``=/`` as a remapping. +files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping. + +An empty remapping prefix is not allowed. If there are multiple matches due to remappings, the one with the longest common prefix is selected. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 836e30d2..e800b278 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -58,22 +58,31 @@ using namespace std; using namespace dev; using namespace dev::solidity; -void CompilerStack::setRemappings(vector<string> const& _remappings) +boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping) +{ + auto eq = find(_remapping.begin(), _remapping.end(), '='); + if (eq == _remapping.end()) + return {}; + + auto colon = find(_remapping.begin(), eq, ':'); + + Remapping r; + + r.context = colon == eq ? string() : string(_remapping.begin(), colon); + r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq); + r.target = string(eq + 1, _remapping.end()); + + if (r.prefix.empty()) + return {}; + + return r; +} + +void CompilerStack::setRemappings(vector<Remapping> const& _remappings) { - vector<Remapping> remappings; for (auto const& remapping: _remappings) - { - auto eq = find(remapping.begin(), remapping.end(), '='); - if (eq == remapping.end()) - continue; // ignore - auto colon = find(remapping.begin(), eq, ':'); - Remapping r; - r.context = colon == eq ? string() : string(remapping.begin(), colon); - r.prefix = colon == eq ? string(remapping.begin(), eq) : string(colon + 1, eq); - r.target = string(eq + 1, remapping.end()); - remappings.push_back(r); - } - swap(m_remappings, remappings); + solAssert(!remapping.prefix.empty(), ""); + m_remappings = _remappings; } void CompilerStack::setEVMVersion(EVMVersion _version) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 2234a8c9..9a15fbf0 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -84,6 +84,13 @@ public: CompilationSuccessful }; + struct Remapping + { + std::string context; + std::string prefix; + std::string target; + }; + /// Creates a new compiler stack. /// @param _readFile callback to used to read files for import statements. Must return /// and must not emit exceptions. @@ -103,8 +110,11 @@ public: /// All settings, with the exception of remappings, are reset. void reset(bool _keepSources = false); - /// Sets path remappings in the format "context:prefix=target" - void setRemappings(std::vector<std::string> const& _remappings); + // Parses a remapping of the format "context:prefix=target". + static boost::optional<Remapping> parseRemapping(std::string const& _remapping); + + /// Sets path remappings. + void setRemappings(std::vector<Remapping> const& _remappings); /// Sets library addresses. Addresses are cleared iff @a _libraries is missing. /// Will not take effect before running compile. @@ -319,13 +329,6 @@ private: FunctionDefinition const& _function ) const; - struct Remapping - { - std::string context; - std::string prefix; - std::string target; - }; - ReadCallback::Callback m_readFile; ReadCallback::Callback m_smtQuery; bool m_optimize = false; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 58b84163..c1996777 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -326,9 +326,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setEVMVersion(*version); } - vector<string> remappings; + vector<CompilerStack::Remapping> remappings; for (auto const& remapping: settings.get("remappings", Json::Value())) - remappings.push_back(remapping.asString()); + { + if (auto r = CompilerStack::parseRemapping(remapping.asString())) + remappings.emplace_back(std::move(*r)); + else + return formatFatalError("JSONError", "Invalid remapping: \"" + remapping.asString() + "\""); + } m_compilerStack.setRemappings(remappings); Json::Value optimizerSettings = settings.get("optimizer", Json::Value()); diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 429bd637..f7d1c748 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -392,7 +392,18 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() { auto eq = find(path.begin(), path.end(), '='); if (eq != path.end()) - path = string(eq + 1, path.end()); + { + if (auto r = CompilerStack::parseRemapping(path)) + { + m_remappings.emplace_back(std::move(*r)); + path = string(eq + 1, path.end()); + } + else + { + cerr << "Invalid remapping: \"" << path << "\"." << endl; + return false; + } + } else if (path == "-") addStdin = true; else @@ -808,7 +819,7 @@ bool CommandLineInterface::processInput() if (m_args.count(g_argMetadataLiteral) > 0) m_compiler->useMetadataLiteralSources(true); if (m_args.count(g_argInputFile)) - m_compiler->setRemappings(m_args[g_argInputFile].as<vector<string>>()); + m_compiler->setRemappings(m_remappings); for (auto const& sourceCode: m_sourceCodes) m_compiler->addSource(sourceCode.first, sourceCode.second); if (m_args.count(g_argLibraries)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 45ec1eb5..010dce34 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -97,6 +97,8 @@ private: boost::program_options::variables_map m_args; /// map of input files to source code strings std::map<std::string, std::string> m_sourceCodes; + /// list of remappings + std::vector<dev::solidity::CompilerStack::Remapping> m_remappings; /// list of allowed directories to read files from std::vector<boost::filesystem::path> m_allowedDirectories; /// map of library names to addresses diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 7256386d..a260da34 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -144,6 +144,10 @@ test_solc_file_input_failures "file_not_found.sol" "" "" "\"file_not_found.sol\" printTask "Testing passing files that are not files..." test_solc_file_input_failures "." "" "" "\".\" is not a valid file." +printTask "Testing passing empty remappings..." +test_solc_file_input_failures "${0}" "=/some/remapping/target" "" "Invalid remapping: \"=/some/remapping/target\"." +test_solc_file_input_failures "${0}" "ctx:=/some/remapping/target" "" "Invalid remapping: \"ctx:=/some/remapping/target\"." + printTask "Compiling various other contracts and libraries..." ( cd "$REPO_ROOT"/test/compilationTests/ diff --git a/test/libsolidity/Imports.cpp b/test/libsolidity/Imports.cpp index df31ac40..dc33d577 100644 --- a/test/libsolidity/Imports.cpp +++ b/test/libsolidity/Imports.cpp @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(name_clash_in_import) BOOST_AUTO_TEST_CASE(remappings) { CompilerStack c; - c.setRemappings(vector<string>{"s=s_1.4.6", "t=Tee"}); + c.setRemappings(vector<CompilerStack::Remapping>{{"", "s", "s_1.4.6"},{"", "t", "Tee"}}); c.addSource("a", "import \"s/s.sol\"; contract A is S {} pragma solidity >=0.0;"); c.addSource("b", "import \"t/tee.sol\"; contract A is Tee {} pragma solidity >=0.0;"); c.addSource("s_1.4.6/s.sol", "contract S {} pragma solidity >=0.0;"); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(remappings) BOOST_AUTO_TEST_CASE(context_dependent_remappings) { CompilerStack c; - c.setRemappings(vector<string>{"a:s=s_1.4.6", "b:s=s_1.4.7"}); + c.setRemappings(vector<CompilerStack::Remapping>{{"a", "s", "s_1.4.6"}, {"b", "s", "s_1.4.7"}}); c.addSource("a/a.sol", "import \"s/s.sol\"; contract A is SSix {} pragma solidity >=0.0;"); c.addSource("b/b.sol", "import \"s/s.sol\"; contract B is SSeven {} pragma solidity >=0.0;"); c.addSource("s_1.4.6/s.sol", "contract SSix {} pragma solidity >=0.0;"); @@ -200,7 +200,11 @@ BOOST_AUTO_TEST_CASE(filename_with_period) BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_preserved) { CompilerStack c; - c.setRemappings(vector<string>{"foo=vendor/foo_2.0.0", "vendor/bar:foo=vendor/foo_1.0.0", "bar=vendor/bar"}); + c.setRemappings(vector<CompilerStack::Remapping>{ + {"", "foo", "vendor/foo_2.0.0"}, + {"vendor/bar", "foo", "vendor/foo_1.0.0"}, + {"", "bar", "vendor/bar"} + }); c.addSource("main.sol", "import \"foo/foo.sol\"; import {Bar} from \"bar/bar.sol\"; contract Main is Foo2, Bar {} pragma solidity >=0.0;"); c.addSource("vendor/bar/bar.sol", "import \"foo/foo.sol\"; contract Bar {Foo1 foo;} pragma solidity >=0.0;"); c.addSource("vendor/foo_1.0.0/foo.sol", "contract Foo1 {} pragma solidity >=0.0;"); @@ -212,7 +216,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_pres BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent) { CompilerStack c; - c.setRemappings(vector<string>{"a:x/y/z=d", "a/b:x=e"}); + c.setRemappings(vector<CompilerStack::Remapping>{{"a", "x/y/z", "d"}, {"a/b", "x", "e"}}); c.addSource("a/main.sol", "import \"x/y/z/z.sol\"; contract Main is D {} pragma solidity >=0.0;"); c.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;"); c.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;"); @@ -220,7 +224,7 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent) c.setEVMVersion(dev::test::Options::get().evmVersion()); BOOST_CHECK(c.compile()); CompilerStack d; - d.setRemappings(vector<string>{"a/b:x=e", "a:x/y/z=d"}); + d.setRemappings(vector<CompilerStack::Remapping>{{"a/b", "x", "e"}, {"a", "x/y/z", "d"}}); d.addSource("a/main.sol", "import \"x/y/z/z.sol\"; contract Main is D {} pragma solidity >=0.0;"); d.addSource("a/b/main.sol", "import \"x/y/z/z.sol\"; contract Main is E {} pragma solidity >=0.0;"); d.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;"); |