Disallow remappings with empty prefix.

This commit is contained in:
Daniel Kirchner 2018-08-09 20:37:49 +02:00
parent 43db88b836
commit 954d7433bd
8 changed files with 71 additions and 32 deletions

View File

@ -16,6 +16,7 @@ Breaking Changes:
* Commandline interface: Remove obsolete ``--formal`` option. * Commandline interface: Remove obsolete ``--formal`` option.
* Commandline interface: Rename the ``--julia`` option to ``--yul``. * Commandline interface: Rename the ``--julia`` option to ``--yul``.
* Commandline interface: Require ``-`` if standard input is used as source. * 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. * 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: ``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. * General: Disallow declaring empty structs.

View File

@ -58,22 +58,31 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::solidity; using namespace dev::solidity;
void CompilerStack::setRemappings(vector<string> const& _remappings) boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
{ {
vector<Remapping> remappings; auto eq = find(_remapping.begin(), _remapping.end(), '=');
for (auto const& remapping: _remappings) if (eq == _remapping.end())
{ return {};
auto eq = find(remapping.begin(), remapping.end(), '=');
if (eq == remapping.end()) auto colon = find(_remapping.begin(), eq, ':');
continue; // ignore
auto colon = find(remapping.begin(), eq, ':');
Remapping r; Remapping r;
r.context = colon == eq ? string() : string(remapping.begin(), colon);
r.prefix = colon == eq ? string(remapping.begin(), eq) : string(colon + 1, eq); r.context = colon == eq ? string() : string(_remapping.begin(), colon);
r.target = string(eq + 1, remapping.end()); r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq);
remappings.push_back(r); r.target = string(eq + 1, _remapping.end());
if (r.prefix.empty())
return {};
return r;
} }
swap(m_remappings, remappings);
void CompilerStack::setRemappings(vector<Remapping> const& _remappings)
{
for (auto const& remapping: _remappings)
solAssert(!remapping.prefix.empty(), "");
m_remappings = _remappings;
} }
void CompilerStack::setEVMVersion(EVMVersion _version) void CompilerStack::setEVMVersion(EVMVersion _version)

View File

@ -84,6 +84,13 @@ public:
CompilationSuccessful CompilationSuccessful
}; };
struct Remapping
{
std::string context;
std::string prefix;
std::string target;
};
/// Creates a new compiler stack. /// Creates a new compiler stack.
/// @param _readFile callback to used to read files for import statements. Must return /// @param _readFile callback to used to read files for import statements. Must return
/// and must not emit exceptions. /// and must not emit exceptions.
@ -103,8 +110,11 @@ public:
/// All settings, with the exception of remappings, are reset. /// All settings, with the exception of remappings, are reset.
void reset(bool _keepSources = false); void reset(bool _keepSources = false);
/// Sets path remappings in the format "context:prefix=target" // Parses a remapping of the format "context:prefix=target".
void setRemappings(std::vector<std::string> const& _remappings); 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. /// Sets library addresses. Addresses are cleared iff @a _libraries is missing.
/// Will not take effect before running compile. /// Will not take effect before running compile.
@ -319,13 +329,6 @@ private:
FunctionDefinition const& _function FunctionDefinition const& _function
) const; ) const;
struct Remapping
{
std::string context;
std::string prefix;
std::string target;
};
ReadCallback::Callback m_readFile; ReadCallback::Callback m_readFile;
ReadCallback::Callback m_smtQuery; ReadCallback::Callback m_smtQuery;
bool m_optimize = false; bool m_optimize = false;

View File

@ -326,9 +326,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.setEVMVersion(*version); m_compilerStack.setEVMVersion(*version);
} }
vector<string> remappings; vector<CompilerStack::Remapping> remappings;
for (auto const& remapping: settings.get("remappings", Json::Value())) 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); m_compilerStack.setRemappings(remappings);
Json::Value optimizerSettings = settings.get("optimizer", Json::Value()); Json::Value optimizerSettings = settings.get("optimizer", Json::Value());

View File

@ -392,7 +392,18 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
{ {
auto eq = find(path.begin(), path.end(), '='); auto eq = find(path.begin(), path.end(), '=');
if (eq != path.end()) if (eq != path.end())
{
if (auto r = CompilerStack::parseRemapping(path))
{
m_remappings.emplace_back(std::move(*r));
path = string(eq + 1, path.end()); path = string(eq + 1, path.end());
}
else
{
cerr << "Invalid remapping: \"" << path << "\"." << endl;
return false;
}
}
else if (path == "-") else if (path == "-")
addStdin = true; addStdin = true;
else else
@ -808,7 +819,7 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argMetadataLiteral) > 0) if (m_args.count(g_argMetadataLiteral) > 0)
m_compiler->useMetadataLiteralSources(true); m_compiler->useMetadataLiteralSources(true);
if (m_args.count(g_argInputFile)) 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) for (auto const& sourceCode: m_sourceCodes)
m_compiler->addSource(sourceCode.first, sourceCode.second); m_compiler->addSource(sourceCode.first, sourceCode.second);
if (m_args.count(g_argLibraries)) if (m_args.count(g_argLibraries))

View File

@ -97,6 +97,8 @@ private:
boost::program_options::variables_map m_args; boost::program_options::variables_map m_args;
/// map of input files to source code strings /// map of input files to source code strings
std::map<std::string, std::string> m_sourceCodes; 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 /// list of allowed directories to read files from
std::vector<boost::filesystem::path> m_allowedDirectories; std::vector<boost::filesystem::path> m_allowedDirectories;
/// map of library names to addresses /// map of library names to addresses

View File

@ -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..." printTask "Testing passing files that are not files..."
test_solc_file_input_failures "." "" "" "\".\" is not a valid file." 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..." printTask "Compiling various other contracts and libraries..."
( (
cd "$REPO_ROOT"/test/compilationTests/ cd "$REPO_ROOT"/test/compilationTests/

View File

@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(name_clash_in_import)
BOOST_AUTO_TEST_CASE(remappings) BOOST_AUTO_TEST_CASE(remappings)
{ {
CompilerStack c; 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("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("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;"); 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) BOOST_AUTO_TEST_CASE(context_dependent_remappings)
{ {
CompilerStack c; 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("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("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;"); 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) BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_preserved)
{ {
CompilerStack c; 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("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/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;"); 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) BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent)
{ {
CompilerStack c; 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/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("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;"); 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()); c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile()); BOOST_CHECK(c.compile());
CompilerStack d; 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/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("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;"); d.addSource("d/z.sol", "contract D {} pragma solidity >=0.0;");