From db98eed5c2079d240100093c9da8c0c7f2442113 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Fri, 13 Oct 2023 10:07:43 +0200 Subject: [PATCH] Introduce --no-import-callback CLI option Add tests Add docs --- Changelog.md | 1 + docs/path-resolution.rst | 5 ++-- libsolidity/interface/UniversalCallback.h | 11 +++++--- solc/CommandLineInterface.cpp | 3 +++ solc/CommandLineInterface.h | 2 +- solc/CommandLineParser.cpp | 12 +++++++++ solc/CommandLineParser.h | 1 + test/cmdlineTests/no_import_callback/args | 1 + .../no_import_callback/contract_1.sol | 4 +++ .../no_import_callback/contract_2.sol | 0 test/cmdlineTests/no_import_callback/err | 5 ++++ test/cmdlineTests/no_import_callback/exit | 1 + .../standard_no_import_callback/B.sol | 2 ++ .../standard_no_import_callback/args | 1 + .../standard_no_import_callback/input.json | 8 ++++++ .../standard_no_import_callback/output.json | 26 +++++++++++++++++++ test/solc/CommandLineInterface.cpp | 19 ++++++++++++++ test/solc/CommandLineParser.cpp | 19 ++++++++++++++ 18 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 test/cmdlineTests/no_import_callback/args create mode 100644 test/cmdlineTests/no_import_callback/contract_1.sol create mode 100644 test/cmdlineTests/no_import_callback/contract_2.sol create mode 100644 test/cmdlineTests/no_import_callback/err create mode 100644 test/cmdlineTests/no_import_callback/exit create mode 100644 test/cmdlineTests/standard_no_import_callback/B.sol create mode 100644 test/cmdlineTests/standard_no_import_callback/args create mode 100644 test/cmdlineTests/standard_no_import_callback/input.json create mode 100644 test/cmdlineTests/standard_no_import_callback/output.json diff --git a/Changelog.md b/Changelog.md index 2f58f42ef708..57175dcc79d3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Language Features: Compiler Features: + * Commandline Interface: Add ``--no-import-callback`` option that prevents the compiler from loading source files not given explicitly on the CLI or in Standard JSON input. * Commandline Interface: Use proper severity and coloring also for error messages produced outside of the compilation pipeline. * Parser: Remove the experimental error recovery mode (``--error-recovery`` / ``settings.parserErrorRecovery``). * Yul Optimizer: If ``PUSH0`` is supported, favor zero literals over storing zero values in variables. diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 1c5a39516fe4..666d9b8dc9ca 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -21,7 +21,7 @@ source unit is assigned a unique *source unit name* which is an opaque and unstr When you use the :ref:`import statement `, you specify an *import path* that references a source unit name. -.. index:: ! import callback, ! Host Filesystem Loader +.. index:: ! import callback, ! Host Filesystem Loader, ! --no-import-callback .. _import-callback: Import Callback @@ -36,8 +36,9 @@ An import callback is free to interpret source unit names in an arbitrary way, n If there is no callback available when one is needed or if it fails to locate the source code, compilation fails. -The command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback +By default, the command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback that interprets a source unit name as a path in the local filesystem. +This callback can be disabled using the ``--no-import-callback`` command-line option. The `JavaScript interface `_ does not provide any by default, but one can be provided by the user. This mechanism can be used to obtain source code from locations other then the local filesystem diff --git a/libsolidity/interface/UniversalCallback.h b/libsolidity/interface/UniversalCallback.h index 1c7888f3971b..3fe74c65e48f 100644 --- a/libsolidity/interface/UniversalCallback.h +++ b/libsolidity/interface/UniversalCallback.h @@ -29,7 +29,7 @@ namespace solidity::frontend class UniversalCallback { public: - UniversalCallback(FileReader& _fileReader, SMTSolverCommand& _solver) : + UniversalCallback(FileReader* _fileReader, SMTSolverCommand& _solver) : m_fileReader{_fileReader}, m_solver{_solver} {} @@ -38,15 +38,20 @@ class UniversalCallback { return [this](std::string const& _kind, std::string const& _data) -> ReadCallback::Result { if (_kind == ReadCallback::kindString(ReadCallback::Kind::ReadFile)) - return m_fileReader.readFile(_kind, _data); + if (!m_fileReader) + return ReadCallback::Result{false, "No import callback."}; + else + return m_fileReader->readFile(_kind, _data); else if (_kind == ReadCallback::kindString(ReadCallback::Kind::SMTQuery)) return m_solver.solve(_kind, _data); solAssert(false, "Unknown callback kind."); }; } + void resetImportCallback() { m_fileReader = nullptr; } + private: - FileReader& m_fileReader; + FileReader* m_fileReader; SMTSolverCommand& m_solver; }; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 7b8763c5a4a1..218f89f02e8b 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -464,6 +464,9 @@ void CommandLineInterface::readInputFiles() { solAssert(!m_standardJsonInput.has_value()); + if (m_options.input.noImportCallback) + m_universalCallback.resetImportCallback(); + static std::set const noInputFiles{ frontend::InputMode::Help, frontend::InputMode::License, diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 32cc8bbefd1c..f08eea662a27 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -144,7 +144,7 @@ class CommandLineInterface bool m_hasOutput = false; FileReader m_fileReader; SMTSolverCommand m_solverCommand{"eld"}; - UniversalCallback m_universalCallback{m_fileReader, m_solverCommand}; + UniversalCallback m_universalCallback{&m_fileReader, m_solverCommand}; std::optional m_standardJsonInput; std::unique_ptr m_compiler; CommandLineOptions m_options; diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 23ceb001ccc2..c21659a9bc35 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -78,6 +78,7 @@ static std::string const g_strModelCheckerTimeout = "model-checker-timeout"; static std::string const g_strModelCheckerBMCLoopIterations = "model-checker-bmc-loop-iterations"; static std::string const g_strNone = "none"; static std::string const g_strNoOptimizeYul = "no-optimize-yul"; +static std::string const g_strNoImportCallback = "no-import-callback"; static std::string const g_strOptimize = "optimize"; static std::string const g_strOptimizeRuns = "optimize-runs"; static std::string const g_strOptimizeYul = "optimize-yul"; @@ -224,6 +225,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex input.includePaths == _other.input.includePaths && input.allowedDirectories == _other.input.allowedDirectories && input.ignoreMissingFiles == _other.input.ignoreMissingFiles && + input.noImportCallback == _other.input.noImportCallback && output.dir == _other.output.dir && output.overwriteFiles == _other.output.overwriteFiles && output.evmVersion == _other.output.evmVersion && @@ -567,6 +569,11 @@ General Information)").c_str(), g_strIgnoreMissingFiles.c_str(), "Ignore missing files." ) + ( + g_strNoImportCallback.c_str(), + "Disable the default import callback to prevent the compiler from loading any source " + "files not listed on the command line or given in the Standard JSON input." + ) ; desc.add(inputOptions); @@ -1104,6 +1111,11 @@ void CommandLineParser::processArgs() } } + checkMutuallyExclusive({g_strNoImportCallback, g_strAllowPaths}); + + if (m_args.count(g_strNoImportCallback)) + m_options.input.noImportCallback = true; + if (m_args.count(g_strAllowPaths)) { std::vector paths; diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 33cb7bb094ef..cad84871e087 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -174,6 +174,7 @@ struct CommandLineOptions std::vector includePaths; FileReader::FileSystemPathSet allowedDirectories; bool ignoreMissingFiles = false; + bool noImportCallback = false; } input; struct diff --git a/test/cmdlineTests/no_import_callback/args b/test/cmdlineTests/no_import_callback/args new file mode 100644 index 000000000000..e816120d0db6 --- /dev/null +++ b/test/cmdlineTests/no_import_callback/args @@ -0,0 +1 @@ +--no-import-callback no_import_callback/contract_1.sol diff --git a/test/cmdlineTests/no_import_callback/contract_1.sol b/test/cmdlineTests/no_import_callback/contract_1.sol new file mode 100644 index 000000000000..36b2470cd3d2 --- /dev/null +++ b/test/cmdlineTests/no_import_callback/contract_1.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +import "contract_2.sol"; diff --git a/test/cmdlineTests/no_import_callback/contract_2.sol b/test/cmdlineTests/no_import_callback/contract_2.sol new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/cmdlineTests/no_import_callback/err b/test/cmdlineTests/no_import_callback/err new file mode 100644 index 000000000000..45690e34c8f2 --- /dev/null +++ b/test/cmdlineTests/no_import_callback/err @@ -0,0 +1,5 @@ +Error: Source "contract_2.sol" not found: No import callback. + --> no_import_callback/contract_1.sol:4:1: + | +4 | import "contract_2.sol"; + | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test/cmdlineTests/no_import_callback/exit b/test/cmdlineTests/no_import_callback/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/no_import_callback/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_no_import_callback/B.sol b/test/cmdlineTests/standard_no_import_callback/B.sol new file mode 100644 index 000000000000..4bf9ea143b54 --- /dev/null +++ b/test/cmdlineTests/standard_no_import_callback/B.sol @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; diff --git a/test/cmdlineTests/standard_no_import_callback/args b/test/cmdlineTests/standard_no_import_callback/args new file mode 100644 index 000000000000..b8edaa4247f1 --- /dev/null +++ b/test/cmdlineTests/standard_no_import_callback/args @@ -0,0 +1 @@ +--no-import-callback diff --git a/test/cmdlineTests/standard_no_import_callback/input.json b/test/cmdlineTests/standard_no_import_callback/input.json new file mode 100644 index 000000000000..229b5fb379a1 --- /dev/null +++ b/test/cmdlineTests/standard_no_import_callback/input.json @@ -0,0 +1,8 @@ +{ + "language": "Solidity", + "sources": { + "A": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; import 'standard_no_import_callback/B.sol';" + } + } +} diff --git a/test/cmdlineTests/standard_no_import_callback/output.json b/test/cmdlineTests/standard_no_import_callback/output.json new file mode 100644 index 000000000000..a4e2d8d3a2bf --- /dev/null +++ b/test/cmdlineTests/standard_no_import_callback/output.json @@ -0,0 +1,26 @@ +{ + "errors": + [ + { + "component": "general", + "errorCode": "6275", + "formattedMessage": "ParserError: Source \"standard_no_import_callback/B.sol\" not found: No import callback. + --> A:2:24: + | +2 | pragma solidity >=0.0; import 'standard_no_import_callback/B.sol'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +", + "message": "Source \"standard_no_import_callback/B.sol\" not found: No import callback.", + "severity": "error", + "sourceLocation": + { + "end": 102, + "file": "A", + "start": 59 + }, + "type": "ParserError" + } + ], + "sources": {} +} diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 9116f7ae6656..6a976df42ac8 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -175,6 +175,25 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes) ); } +BOOST_AUTO_TEST_CASE(no_import_callback_allowed_paths) +{ + array options = { + "--no-import-callback", + "--allow-paths" + }; + + string expectedMessage = + "The following options are mutually exclusive: " + "--no-import-callback, --allow-paths. " + "Select at most one."; + + BOOST_CHECK_EXCEPTION( + parseCommandLineAndReadInputFiles({"solc", options[0], options[1], "."}), + CommandLineValidationError, + [&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; } + ); +} + BOOST_AUTO_TEST_CASE(cli_input) { TemporaryDirectory tempDir1(TEST_CASE_NAME); diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 43cef9d27ada..caad98f999a2 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -241,6 +241,25 @@ BOOST_AUTO_TEST_CASE(no_cbor_metadata) BOOST_TEST(assert); } +BOOST_AUTO_TEST_CASE(no_import_callback) +{ + std::vector> commandLinePerInputMode = { + {"solc", "--no-import-callback", "contract.sol"}, + {"solc", "--standard-json", "--no-import-callback", "input.json"}, + {"solc", "--assemble", "--no-import-callback", "input.yul"}, + {"solc", "--strict-assembly", "--no-import-callback", "input.yul"}, + {"solc", "--import-ast", "--no-import-callback", "ast.json"}, + {"solc", "--link", "--no-import-callback", "input.bin"}, + {"solc", "--yul", "--no-import-callback", "input.yul"}, + }; + + for (auto const& commandLine: commandLinePerInputMode) + { + CommandLineOptions parsedOptions = parseCommandLine(commandLine); + BOOST_TEST(parsedOptions.input.noImportCallback); + } +} + BOOST_AUTO_TEST_CASE(via_ir_options) { BOOST_TEST(!parseCommandLine({"solc", "contract.sol"}).output.viaIR);