mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #4793 from ethereum/emptyRemappings
Disallow remappings with empty prefix.
This commit is contained in:
		
						commit
						a2c754b3fe
					
				| @ -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. | ||||
|  | ||||
| @ -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. | ||||
|  | ||||
| @ -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. | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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()); | ||||
|  | ||||
| @ -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)) | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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/ | ||||
|  | ||||
| @ -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;"); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user