mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11688 from ethereum/fix-and-document-allow-paths
Fix and document `--allow-paths`
This commit is contained in:
commit
39eb182ccc
@ -21,6 +21,7 @@ Bugfixes:
|
||||
* Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly.
|
||||
* Code Generator: Use stable source order for ABI functions.
|
||||
* Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes.
|
||||
* Commandline Interface: Fix resolution of paths whitelisted with ``--allowed-paths`` or implicitly due to base path, remappings and files being compiled. Correctly handle paths that do not match imports exactly due to being relative, non-normalized or empty.
|
||||
* Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them.
|
||||
* 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.
|
||||
* Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code.
|
||||
|
@ -297,7 +297,7 @@ Here are some examples of what you can expect if they are not:
|
||||
The same effect can be achieved in a more reliable way by using direct imports with
|
||||
:ref:`base path <base-path>` and :ref:`import remapping <import-remapping>`.
|
||||
|
||||
.. index:: ! base path, --base-path
|
||||
.. index:: ! base path, ! --base-path
|
||||
.. _base-path:
|
||||
|
||||
Base Path
|
||||
@ -373,6 +373,72 @@ The resulting file path becomes the source unit name.
|
||||
When working with older versions of the compiler it is recommended to invoke the compiler from
|
||||
the base path and to only use relative paths on the command line.
|
||||
|
||||
.. index:: ! allowed paths, ! --allow-paths, remapping; target
|
||||
.. _allowed-paths:
|
||||
|
||||
Allowed Paths
|
||||
=============
|
||||
|
||||
As a security measure, the Host Filesystem Loader will refuse to load files from outside of a few
|
||||
locations that are considered safe by default:
|
||||
|
||||
- Outside of Standard JSON mode:
|
||||
|
||||
- The directories containing input files listed on the command line.
|
||||
- The directories used as :ref:`remapping <import-remapping>` targets.
|
||||
If the target is not a directory (i.e does not end with ``/``, ``/.`` or ``/..``) the directory
|
||||
containing the target is used instead.
|
||||
- Base path.
|
||||
|
||||
- In Standard JSON mode:
|
||||
|
||||
- Base path.
|
||||
|
||||
Additional directories can be whitelisted using the ``--allow-paths`` option.
|
||||
The option accepts a comma-separated list of paths:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd /home/user/project/
|
||||
solc token/contract.sol \
|
||||
lib/util.sol=libs/util.sol \
|
||||
--base-path=token/ \
|
||||
--allow-paths=../utils/,/tmp/libraries
|
||||
|
||||
When the compiler is invoked with the command shown above, the Host Filesystem Loader will allow
|
||||
importing files from the following directories:
|
||||
|
||||
- ``/home/user/project/token/`` (because ``token/`` contains the input file and also because it is
|
||||
the base path),
|
||||
- ``/home/user/project/libs/`` (because ``libs/`` is a directory containing a remapping target),
|
||||
- ``/home/user/utils/`` (because of ``../utils/`` passed to ``--allow-paths``),
|
||||
- ``/tmp/libraries/`` (because of ``/tmp/libraries`` passed to ``--allow-paths``),
|
||||
|
||||
.. note::
|
||||
|
||||
The working directory of the compiler is one of the paths allowed by default only if it
|
||||
happens to be the base path (or the base path is not specified or has an empty value).
|
||||
|
||||
.. note::
|
||||
|
||||
The compiler does not check if allowed paths actually exist and whether they are directories.
|
||||
Non-existent or empty paths are simply ignored.
|
||||
If an allowed path matches a file rather than a directory, the file is considered whitelisted, too.
|
||||
|
||||
.. note::
|
||||
|
||||
Allowed paths are case-sensitive even if the filesystem is not.
|
||||
The case must exactly match the one used in your imports.
|
||||
For example ``--allow-paths tokens`` will not match ``import "Tokens/IERC20.sol"``.
|
||||
|
||||
.. warning::
|
||||
|
||||
Files and directories only reachable through symbolic links from allowed directories are not
|
||||
automatically whitelisted.
|
||||
For example if ``token/contract.sol`` in the example above was actually a symlink pointing at
|
||||
``/etc/passwd`` the compiler would refuse to load it unless ``/etc/`` was one of the allowed
|
||||
paths too.
|
||||
|
||||
.. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target
|
||||
.. _import-remapping:
|
||||
|
||||
|
@ -47,16 +47,13 @@ it is also possible to provide :ref:`path redirects <import-remapping>` using ``
|
||||
|
||||
This essentially instructs the compiler to search for anything starting with
|
||||
``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.
|
||||
|
||||
When accessing the filesystem to search for imports, :ref:`paths that do not start with ./
|
||||
or ../ <relative-imports>` are treated as relative to the directory specified using
|
||||
or ../ <direct-imports>` are treated as relative to the directory specified using
|
||||
``--base-path`` option (or the current working directory if base path is not specified).
|
||||
Furthermore, the part added via ``--base-path`` will not appear in the contract metadata.
|
||||
|
||||
For security reasons the compiler has restrictions on what directories it can access.
|
||||
For security reasons the compiler has :ref:`restrictions on what directories it can access <allowed-paths>`.
|
||||
Directories of source files specified on the command line and target paths of
|
||||
remappings are automatically allowed to be accessed by the file reader, but everything
|
||||
else is rejected by default.
|
||||
|
@ -33,11 +33,29 @@ using std::string;
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
FileReader::FileReader(
|
||||
boost::filesystem::path _basePath,
|
||||
FileSystemPathSet _allowedDirectories
|
||||
):
|
||||
m_allowedDirectories(std::move(_allowedDirectories)),
|
||||
m_sourceCodes()
|
||||
{
|
||||
setBasePath(_basePath);
|
||||
for (boost::filesystem::path const& allowedDir: m_allowedDirectories)
|
||||
solAssert(!allowedDir.empty(), "");
|
||||
}
|
||||
|
||||
void FileReader::setBasePath(boost::filesystem::path const& _path)
|
||||
{
|
||||
m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path));
|
||||
}
|
||||
|
||||
void FileReader::allowDirectory(boost::filesystem::path _path)
|
||||
{
|
||||
solAssert(!_path.empty(), "");
|
||||
m_allowedDirectories.insert(std::move(_path));
|
||||
}
|
||||
|
||||
void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source)
|
||||
{
|
||||
boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path);
|
||||
@ -69,20 +87,17 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
if (strippedSourceUnitName.find("file://") == 0)
|
||||
strippedSourceUnitName.erase(0, 7);
|
||||
|
||||
auto canonicalPath = boost::filesystem::weakly_canonical(m_basePath / strippedSourceUnitName);
|
||||
auto canonicalPath = normalizeCLIPathForVFS(m_basePath / strippedSourceUnitName, SymlinkResolution::Enabled);
|
||||
FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath};
|
||||
|
||||
bool isAllowed = false;
|
||||
for (auto const& allowedDir: m_allowedDirectories)
|
||||
{
|
||||
// If dir is a prefix of boostPath, we are fine.
|
||||
if (
|
||||
std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
|
||||
std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
|
||||
)
|
||||
for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths)
|
||||
if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), canonicalPath))
|
||||
{
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAllowed)
|
||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||
|
||||
@ -101,13 +116,20 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
{
|
||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||
}
|
||||
catch (std::exception const& _exception)
|
||||
{
|
||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::path const& _path)
|
||||
boost::filesystem::path FileReader::normalizeCLIPathForVFS(
|
||||
boost::filesystem::path const& _path,
|
||||
SymlinkResolution _symlinkResolution
|
||||
)
|
||||
{
|
||||
// Detailed normalization rules:
|
||||
// - Makes the path either be absolute or have slash as root (note that on Windows paths with
|
||||
@ -121,7 +143,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa
|
||||
// path to the current working directory.
|
||||
//
|
||||
// Also note that this function:
|
||||
// - Does NOT resolve symlinks (except for symlinks in the path to the current working directory).
|
||||
// - Does NOT resolve symlinks (except for symlinks in the path to the current working directory)
|
||||
// unless explicitly requested.
|
||||
// - Does NOT check if the path refers to a file or a directory. If the path ends with a slash,
|
||||
// the slash is preserved even if it's a file.
|
||||
// - The only exception are paths where the file name is a dot (e.g. '.' or 'a/b/.'). These
|
||||
@ -135,9 +158,27 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa
|
||||
// Windows it does not. To get consistent results we resolve them on all platforms.
|
||||
boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, canonicalWorkDir);
|
||||
|
||||
boost::filesystem::path normalizedPath;
|
||||
if (_symlinkResolution == SymlinkResolution::Enabled)
|
||||
{
|
||||
// NOTE: weakly_canonical() will not convert a relative path into an absolute one if no
|
||||
// directory included in the path actually exists.
|
||||
normalizedPath = boost::filesystem::weakly_canonical(absolutePath);
|
||||
|
||||
// The three corner cases in which lexically_normal() includes a trailing slash in the
|
||||
// normalized path but weakly_canonical() does not. Note that the trailing slash is not
|
||||
// ignored when comparing paths with ==.
|
||||
if ((_path == "." || _path == "./" || _path == "../") && !boost::ends_with(normalizedPath.generic_string(), "/"))
|
||||
normalizedPath = normalizedPath.parent_path() / (normalizedPath.filename().string() + "/");
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(_symlinkResolution == SymlinkResolution::Disabled, "");
|
||||
|
||||
// NOTE: boost path preserves certain differences that are ignored by its operator ==.
|
||||
// E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences.
|
||||
boost::filesystem::path normalizedPath = absolutePath.lexically_normal();
|
||||
normalizedPath = absolutePath.lexically_normal();
|
||||
}
|
||||
solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", "");
|
||||
|
||||
// If the path is on the same drive as the working dir, for portability we prefer not to
|
||||
|
@ -39,22 +39,19 @@ public:
|
||||
using PathMap = std::map<SourceUnitName, boost::filesystem::path>;
|
||||
using FileSystemPathSet = std::set<boost::filesystem::path>;
|
||||
|
||||
enum SymlinkResolution {
|
||||
Disabled, ///< Do not resolve symbolic links in the path.
|
||||
Enabled, ///< Follow symbolic links. The path should contain no symlinks.
|
||||
};
|
||||
|
||||
/// Constructs a FileReader with a base path and a set of allowed directories that
|
||||
/// will be used when requesting files from this file reader instance.
|
||||
explicit FileReader(
|
||||
boost::filesystem::path _basePath = {},
|
||||
FileSystemPathSet _allowedDirectories = {}
|
||||
):
|
||||
m_allowedDirectories(std::move(_allowedDirectories)),
|
||||
m_sourceCodes()
|
||||
{
|
||||
setBasePath(_basePath);
|
||||
}
|
||||
explicit FileReader(boost::filesystem::path _basePath = {}, FileSystemPathSet _allowedDirectories = {});
|
||||
|
||||
void setBasePath(boost::filesystem::path const& _path);
|
||||
boost::filesystem::path const& basePath() const noexcept { return m_basePath; }
|
||||
|
||||
void allowDirectory(boost::filesystem::path _path) { m_allowedDirectories.insert(std::move(_path)); }
|
||||
void allowDirectory(boost::filesystem::path _path);
|
||||
FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; }
|
||||
|
||||
StringMap const& sourceCodes() const noexcept { return m_sourceCodes; }
|
||||
@ -90,11 +87,16 @@ public:
|
||||
|
||||
/// Normalizes a filesystem path to make it include all components up to the filesystem root,
|
||||
/// remove small, inconsequential differences that do not affect the meaning and make it look
|
||||
/// the same on all platforms (if possible). Symlinks in the path are not resolved.
|
||||
/// the same on all platforms (if possible).
|
||||
/// The resulting path uses forward slashes as path separators, has no redundant separators,
|
||||
/// has no redundant . or .. segments and has no root name if removing it does not change the meaning.
|
||||
/// The path does not have to actually exist.
|
||||
static boost::filesystem::path normalizeCLIPathForVFS(boost::filesystem::path const& _path);
|
||||
/// @param _path Path to normalize.
|
||||
/// @param _symlinkResolution If @a Disabled, any symlinks present in @a _path are preserved.
|
||||
static boost::filesystem::path normalizeCLIPathForVFS(
|
||||
boost::filesystem::path const& _path,
|
||||
SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled
|
||||
);
|
||||
|
||||
/// @returns true if all the path components of @a _prefix are present at the beginning of @a _path.
|
||||
/// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no
|
||||
|
@ -20,10 +20,12 @@
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
using std::equal;
|
||||
using std::find;
|
||||
using std::move;
|
||||
using std::nullopt;
|
||||
using std::optional;
|
||||
using std::string;
|
||||
using std::string;
|
||||
using std::string_view;
|
||||
using std::vector;
|
||||
|
||||
namespace solidity::frontend
|
||||
@ -77,24 +79,29 @@ SourceUnitName ImportRemapper::apply(ImportPath const& _path, string const& _con
|
||||
return path;
|
||||
}
|
||||
|
||||
optional<ImportRemapper::Remapping> ImportRemapper::parseRemapping(string const& _remapping)
|
||||
bool ImportRemapper::isRemapping(string_view _input)
|
||||
{
|
||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
||||
if (eq == _remapping.end())
|
||||
return {};
|
||||
return _input.find("=") != string::npos;
|
||||
}
|
||||
|
||||
auto colon = find(_remapping.begin(), eq, ':');
|
||||
optional<ImportRemapper::Remapping> ImportRemapper::parseRemapping(string_view _input)
|
||||
{
|
||||
auto equals = find(_input.cbegin(), _input.cend(), '=');
|
||||
if (equals == _input.end())
|
||||
return nullopt;
|
||||
|
||||
Remapping r;
|
||||
auto const colon = find(_input.cbegin(), equals, ':');
|
||||
|
||||
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());
|
||||
Remapping remapping{
|
||||
(colon == equals ? "" : string(_input.cbegin(), colon)),
|
||||
(colon == equals ? string(_input.cbegin(), equals) : string(colon + 1, equals)),
|
||||
string(equals + 1, _input.cend()),
|
||||
};
|
||||
|
||||
if (r.prefix.empty())
|
||||
return {};
|
||||
if (remapping.prefix.empty())
|
||||
return nullopt;
|
||||
|
||||
return r;
|
||||
return remapping;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,8 +56,11 @@ public:
|
||||
|
||||
SourceUnitName apply(ImportPath const& _path, std::string const& _context) const;
|
||||
|
||||
// Parses a remapping of the format "context:prefix=target".
|
||||
static std::optional<Remapping> parseRemapping(std::string const& _remapping);
|
||||
/// @returns true if the string can be parsed as a remapping
|
||||
static bool isRemapping(std::string_view _input);
|
||||
|
||||
/// Parses a remapping of the format "context:prefix=target".
|
||||
static std::optional<Remapping> parseRemapping(std::string_view _input);
|
||||
|
||||
private:
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
|
@ -338,11 +338,17 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
||||
m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0);
|
||||
|
||||
if (m_args.count(g_strInputFile))
|
||||
for (string path: m_args[g_strInputFile].as<vector<string>>())
|
||||
for (string const& positionalArg: m_args[g_strInputFile].as<vector<string>>())
|
||||
{
|
||||
auto eq = find(path.begin(), path.end(), '=');
|
||||
if (eq != path.end())
|
||||
if (ImportRemapper::isRemapping(positionalArg))
|
||||
{
|
||||
optional<ImportRemapper::Remapping> remapping = ImportRemapper::parseRemapping(positionalArg);
|
||||
if (!remapping.has_value())
|
||||
{
|
||||
serr() << "Invalid remapping: \"" << positionalArg << "\"." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.input.mode == InputMode::StandardJson)
|
||||
{
|
||||
serr() << "Import remappings are not accepted on the command line in Standard JSON mode." << endl;
|
||||
@ -350,21 +356,24 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto r = ImportRemapper::parseRemapping(path))
|
||||
m_options.input.remappings.emplace_back(std::move(*r));
|
||||
else
|
||||
if (!remapping->target.empty())
|
||||
{
|
||||
serr() << "Invalid remapping: \"" << path << "\"." << endl;
|
||||
return false;
|
||||
// If the target is a directory, whitelist it. Otherwise whitelist containing dir.
|
||||
// NOTE: /a/b/c/ is a directory while /a/b/c is not.
|
||||
boost::filesystem::path remappingDir = remapping->target;
|
||||
if (remappingDir.filename() != "..")
|
||||
// As an exception we'll treat /a/b/c/.. as a directory too. It would be
|
||||
// unintuitive to whitelist /a/b/c when the target is equivalent to /a/b/.
|
||||
remappingDir.remove_filename();
|
||||
m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir);
|
||||
}
|
||||
|
||||
string remappingTarget(eq + 1, path.end());
|
||||
m_options.input.allowedDirectories.insert(boost::filesystem::path(remappingTarget).remove_filename());
|
||||
m_options.input.remappings.emplace_back(move(remapping.value()));
|
||||
}
|
||||
else if (path == "-")
|
||||
else if (positionalArg == "-")
|
||||
m_options.input.addStdin = true;
|
||||
else
|
||||
m_options.input.paths.insert(path);
|
||||
m_options.input.paths.insert(positionalArg);
|
||||
}
|
||||
|
||||
if (m_options.input.mode == InputMode::StandardJson)
|
||||
@ -977,17 +986,9 @@ bool CommandLineParser::processArgs()
|
||||
if (m_args.count(g_strAllowPaths))
|
||||
{
|
||||
vector<string> paths;
|
||||
for (string const& path: boost::split(paths, m_args[g_strAllowPaths].as<string>(), boost::is_any_of(",")))
|
||||
{
|
||||
auto filesystem_path = boost::filesystem::path(path);
|
||||
// If the given path had a trailing slash, the Boost filesystem
|
||||
// path will have it's last component set to '.'. This breaks
|
||||
// path comparison in later parts of the code, so we need to strip
|
||||
// it.
|
||||
if (filesystem_path.filename() == ".")
|
||||
filesystem_path.remove_filename();
|
||||
m_options.input.allowedDirectories.insert(filesystem_path);
|
||||
}
|
||||
for (string const& allowedPath: boost::split(paths, m_args[g_strAllowPaths].as<string>(), boost::is_any_of(",")))
|
||||
if (!allowedPath.empty())
|
||||
m_options.input.allowedDirectories.insert(allowedPath);
|
||||
}
|
||||
|
||||
if (m_args.count(g_strStopAfter))
|
||||
|
@ -160,6 +160,7 @@ set(solcli_sources
|
||||
solc/Common.cpp
|
||||
solc/Common.h
|
||||
solc/CommandLineInterface.cpp
|
||||
solc/CommandLineInterfaceAllowPaths.cpp
|
||||
solc/CommandLineParser.cpp
|
||||
)
|
||||
detect_stray_source_files("${solcli_sources}" "solc/")
|
||||
|
@ -53,13 +53,17 @@ void solidity::test::createFileWithContent(boost::filesystem::path const& _path,
|
||||
}
|
||||
|
||||
bool solidity::test::createSymlinkIfSupportedByFilesystem(
|
||||
boost::filesystem::path const& _targetPath,
|
||||
boost::filesystem::path _targetPath,
|
||||
boost::filesystem::path const& _linkName,
|
||||
bool _directorySymlink
|
||||
)
|
||||
{
|
||||
boost::system::error_code symlinkCreationError;
|
||||
|
||||
// NOTE: On Windows / works as a separator in a symlink target only if the target is absolute.
|
||||
// Convert path separators to native ones to avoid this problem.
|
||||
_targetPath.make_preferred();
|
||||
|
||||
if (_directorySymlink)
|
||||
boost::filesystem::create_directory_symlink(_targetPath, _linkName, symlinkCreationError);
|
||||
else
|
||||
|
@ -46,7 +46,7 @@ void createFileWithContent(boost::filesystem::path const& _path, std::string con
|
||||
/// support symlinks.
|
||||
/// Throws an exception of the operation fails for a different reason.
|
||||
bool createSymlinkIfSupportedByFilesystem(
|
||||
boost::filesystem::path const& _targetPath,
|
||||
boost::filesystem::path _targetPath,
|
||||
boost::filesystem::path const& _linkName,
|
||||
bool _directorySymlink
|
||||
);
|
||||
|
@ -1 +0,0 @@
|
||||
-
|
@ -1,11 +0,0 @@
|
||||
Error: Source "too_long_line/input.sol" not found: File outside of allowed directories.
|
||||
--> <stdin>:4:1:
|
||||
|
|
||||
4 | import "../too_long_line/input.sol";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Error: Source "error_codes/input.sol" not found: File outside of allowed directories.
|
||||
--> stdin_allowed_paths/input.sol:4:1:
|
||||
|
|
||||
4 | import "../error_codes/input.sol";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@ -1 +0,0 @@
|
||||
1
|
@ -1,4 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
import "../error_codes/input.sol";
|
@ -1,4 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
import "../too_long_line/input.sol";
|
@ -36,31 +36,39 @@ using namespace solidity::test;
|
||||
namespace solidity::frontend::test
|
||||
{
|
||||
|
||||
using SymlinkResolution = FileReader::SymlinkResolution;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(FileReaderTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./."), "/");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./.", resolveSymlinks), "/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/"), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/."), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/"), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/."), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b"), "/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a", resolveSymlinks), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/", resolveSymlinks), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/.", resolveSymlinks), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a", resolveSymlinks), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/", resolveSymlinks), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/.", resolveSymlinks), "/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b", resolveSymlinks), "/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/", resolveSymlinks), "/a/b/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/.."), "/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/..", resolveSymlinks), "/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../", resolveSymlinks), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/");
|
||||
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../", resolveSymlinks), "/");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path)
|
||||
@ -75,54 +83,64 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path)
|
||||
expectedPrefix = "/" / expectedPrefix.relative_path();
|
||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("."), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./"), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//"), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), expectedPrefix / "x/y");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), expectedPrefix / "x/y/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//"), expectedPrefix / "x/y/");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//", resolveSymlinks), expectedPrefix / "x/y/z/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), expectedPrefix / "x/y");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), expectedPrefix / "x/y/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//", resolveSymlinks), expectedPrefix / "x/y/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a"), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/."), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a"), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/."), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./."), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b"), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/"), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./.", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b"), expectedPrefix / "x/y/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b"), expectedPrefix / "x/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b"), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b"), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b", resolveSymlinks), expectedPrefix / "x/y/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b", resolveSymlinks), expectedPrefix / "x/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/"), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/"), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/.."), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../"), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//"), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../.."), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../"), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//"), expectedPrefix / "x/y/z/a/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b"), expectedPrefix / "a/b");
|
||||
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||
#endif
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..", resolveSymlinks), expectedPrefix / "x/y/z/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//", resolveSymlinks), expectedPrefix / "x/y/z/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..", resolveSymlinks), expectedPrefix / "x/y/z/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//", resolveSymlinks), expectedPrefix / "x/y/z/a/");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////"), "/");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////", resolveSymlinks), "/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////"), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/", resolveSymlinks), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/", resolveSymlinks), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/", resolveSymlinks), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//", resolveSymlinks), "/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////", resolveSymlinks), "/a/b/");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path)
|
||||
@ -134,24 +152,27 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path)
|
||||
boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path();
|
||||
soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", "");
|
||||
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
// UNC paths start with // or \\ followed by a name. They are used for network shares on Windows.
|
||||
// On UNIX systems they are not supported but still treated in a special way.
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/"), "//host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b"), "//host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/"), "//host/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/", resolveSymlinks), "//host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b", resolveSymlinks), "//host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/", resolveSymlinks), "//host/a/b/");
|
||||
|
||||
#if defined(_WIN32)
|
||||
// On Windows an UNC path can also start with \\ instead of //
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), "//host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), "//host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), "//host/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), "//host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), "//host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), "//host/a/b/");
|
||||
#else
|
||||
// On UNIX systems it's just a fancy relative path instead
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), expectedWorkDir / "\\\\host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), expectedWorkDir / "\\\\host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), expectedWorkDir / "\\\\host/a/b/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), expectedWorkDir / "\\\\host/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), expectedWorkDir / "\\\\host/a/b");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), expectedWorkDir / "\\\\host/a/b/");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
||||
{
|
||||
@ -167,21 +188,24 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
||||
// C:\ represents the root directory of drive C: but C: on its own refers to the current working
|
||||
// directory.
|
||||
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
// UNC paths
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//"), "//" / expectedWorkDir);
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host"), "//host" / expectedWorkDir);
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//", resolveSymlinks), "//" / expectedWorkDir);
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host", resolveSymlinks), "//host" / expectedWorkDir);
|
||||
|
||||
// On UNIX systems root name is empty.
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(""), expectedWorkDir);
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("", resolveSymlinks), expectedWorkDir);
|
||||
|
||||
#if defined(_WIN32)
|
||||
boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name();
|
||||
solAssert(!driveLetter.empty(), "");
|
||||
solAssert(driveLetter.is_relative(), "");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter), expectedWorkDir);
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter, resolveSymlinks), expectedWorkDir);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
||||
{
|
||||
@ -193,41 +217,55 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
||||
soltestAssert(!boost::filesystem::current_path().root_name().empty(), "");
|
||||
#endif
|
||||
|
||||
boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path());
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(
|
||||
boost::filesystem::current_path(),
|
||||
resolveSymlinks
|
||||
);
|
||||
BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path());
|
||||
BOOST_TEST(normalizedPath.root_name().empty());
|
||||
BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root)
|
||||
{
|
||||
TemporaryWorkingDirectory tempWorkDir("/");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../.."), "/");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a", resolveSymlinks), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a");
|
||||
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../..", resolveSymlinks), "/");
|
||||
#endif
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a"), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../.."), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a", resolveSymlinks), "/a");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a");
|
||||
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../..", resolveSymlinks), "/");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../..", resolveSymlinks), "/");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity)
|
||||
@ -235,22 +273,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity)
|
||||
TemporaryDirectory tempDir(TEST_CASE_NAME);
|
||||
TemporaryWorkingDirectory tempWorkDir(tempDir);
|
||||
|
||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||
boost::filesystem::path workDirNoSymlinks = boost::filesystem::weakly_canonical(tempDir);
|
||||
boost::filesystem::path expectedPrefix = "/" / workDirNoSymlinks.relative_path();
|
||||
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") == expectedPrefix / "abc");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") != expectedPrefix / "ABC");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") != expectedPrefix / "abc");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") == expectedPrefix / "ABC");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) == expectedPrefix / "abc");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) != expectedPrefix / "ABC");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) != expectedPrefix / "abc");
|
||||
BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) == expectedPrefix / "ABC");
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators)
|
||||
{
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
// Even on Windows we want / as a separator.
|
||||
BOOST_TEST((FileReader::normalizeCLIPathForVFS("/a/b/c").native() == boost::filesystem::path("/a/b/c").native()));
|
||||
BOOST_TEST((
|
||||
FileReader::normalizeCLIPathForVFS("/a/b/c", resolveSymlinks).native() ==
|
||||
boost::filesystem::path("/a/b/c").native()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks)
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks_unless_requested)
|
||||
{
|
||||
TemporaryDirectory tempDir({"abc/"}, TEST_CASE_NAME);
|
||||
soltestAssert(tempDir.path().is_absolute(), "");
|
||||
@ -258,11 +305,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks)
|
||||
if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true))
|
||||
return;
|
||||
|
||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||
boost::filesystem::path expectedPrefixWithSymlinks = "/" / tempDir.path().relative_path();
|
||||
boost::filesystem::path expectedPrefixWithoutSymlinks = "/" / boost::filesystem::weakly_canonical(tempDir).relative_path();
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol");
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled),
|
||||
expectedPrefixWithSymlinks / "sym/contract.sol"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled),
|
||||
expectedPrefixWithSymlinks / "abc/contract.sol"
|
||||
);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled),
|
||||
expectedPrefixWithoutSymlinks / "abc/contract.sol"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled),
|
||||
expectedPrefixWithoutSymlinks / "abc/contract.sol"
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative)
|
||||
@ -280,9 +342,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_w
|
||||
boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path();
|
||||
soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", "");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("contract.sol"), expectedWorkDir / "contract.sol");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol");
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol");
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS("contract.sol", resolveSymlinks),
|
||||
expectedWorkDir / "contract.sol"
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled),
|
||||
expectedPrefix / "sym/contract.sol"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled),
|
||||
expectedPrefix / "abc/contract.sol"
|
||||
);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled),
|
||||
expectedWorkDir / "contract.sol"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(
|
||||
FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled),
|
||||
expectedWorkDir / "contract.sol"
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix)
|
||||
|
@ -786,12 +786,7 @@ BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_symlinks)
|
||||
TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "r");
|
||||
|
||||
if (
|
||||
#if !defined(_WIN32)
|
||||
!createSymlinkIfSupportedByFilesystem("../x/y", tempDir.path() / "r/sym", true) ||
|
||||
#else
|
||||
// NOTE: On Windows / works as a separator in a symlink target only if the target is absolute
|
||||
!createSymlinkIfSupportedByFilesystem("..\\x\\y", tempDir.path() / "r/sym", true) ||
|
||||
#endif
|
||||
!createSymlinkIfSupportedByFilesystem("contract.sol", tempDir.path() / "x/y/z/contract_symlink.sol", false)
|
||||
)
|
||||
return;
|
||||
|
539
test/solc/CommandLineInterfaceAllowPaths.cpp
Normal file
539
test/solc/CommandLineInterfaceAllowPaths.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
/// Unit tests for solc/CommandLineInterface.h
|
||||
|
||||
#include <solc/CommandLineInterface.h>
|
||||
|
||||
#include <test/solc/Common.h>
|
||||
|
||||
#include <test/Common.h>
|
||||
#include <test/FilesystemUtils.h>
|
||||
#include <test/TemporaryDirectory.h>
|
||||
#include <test/libsolidity/util/SoltestErrors.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::test;
|
||||
|
||||
#define TEST_CASE_NAME (boost::unit_test::framework::current_test_case().p_name)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ImportCheck
|
||||
{
|
||||
enum class Result
|
||||
{
|
||||
Unknown, ///< Status is unknown due to a failure of the status check.
|
||||
OK, ///< Passed compilation without errors.
|
||||
FileNotFound, ///< Error was reported: file not found.
|
||||
PathDisallowed, ///< Error was reported: file not allowed paths.
|
||||
};
|
||||
|
||||
bool operator==(ImportCheck const& _other) const { return result == _other.result && message == _other.message; }
|
||||
bool operator!=(ImportCheck const& _other) const { return !(*this == _other); }
|
||||
|
||||
operator bool() const { return this->result == Result::OK; }
|
||||
|
||||
static ImportCheck const OK() { return {Result::OK, ""}; }
|
||||
static ImportCheck const FileNotFound() { return {Result::FileNotFound, ""}; }
|
||||
static ImportCheck const PathDisallowed() { return {Result::PathDisallowed, ""}; }
|
||||
static ImportCheck const Unknown(const string& _message) { return {Result::Unknown, _message}; }
|
||||
|
||||
Result result;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
ImportCheck checkImport(
|
||||
string const& _import,
|
||||
vector<string> const& _cliOptions
|
||||
)
|
||||
{
|
||||
soltestAssert(regex_match(_import, regex{R"(import '[^']*')"}), "");
|
||||
for (string const& option: _cliOptions)
|
||||
soltestAssert(
|
||||
boost::starts_with(option, "--base-path") ||
|
||||
boost::starts_with(option, "--allow-paths") ||
|
||||
!boost::starts_with(option, "--"),
|
||||
""
|
||||
);
|
||||
|
||||
vector<string> commandLine = {
|
||||
"solc",
|
||||
"-",
|
||||
"--no-color",
|
||||
"--error-codes",
|
||||
};
|
||||
commandLine += _cliOptions;
|
||||
|
||||
string standardInputContent =
|
||||
"// SPDX-License-Identifier: GPL-3.0\n"
|
||||
"pragma solidity >=0.0;\n" +
|
||||
_import + ";";
|
||||
|
||||
test::OptionsReaderAndMessages cliResult = test::parseCommandLineAndReadInputFiles(
|
||||
commandLine,
|
||||
standardInputContent,
|
||||
true /* processInput */
|
||||
);
|
||||
if (cliResult.success)
|
||||
return ImportCheck::OK();
|
||||
|
||||
static regex const sourceNotFoundErrorRegex{
|
||||
R"(^Error \(6275\): Source ".+" not found: (.*)\.\n)"
|
||||
R"(\s*--> .*<stdin>:\d+:\d+:\n)"
|
||||
R"(\s*\|\n)"
|
||||
R"(\d+\s*\| import '.+';\n)"
|
||||
R"(\s*\| \^+\n\s*$)"
|
||||
};
|
||||
|
||||
smatch submatches;
|
||||
if (!regex_match(cliResult.stderrContent, submatches, sourceNotFoundErrorRegex))
|
||||
return ImportCheck::Unknown("Unexpected stderr content: '" + cliResult.stderrContent + "'");
|
||||
if (submatches[1] != "File not found" && submatches[1] != "File outside of allowed directories")
|
||||
return ImportCheck::Unknown("Unexpected error message: '" + cliResult.stderrContent + "'");
|
||||
|
||||
if (submatches[1] == "File not found")
|
||||
return ImportCheck::FileNotFound();
|
||||
else if (submatches[1] == "File outside of allowed directories")
|
||||
return ImportCheck::PathDisallowed();
|
||||
else
|
||||
return ImportCheck::Unknown("Unexpected error message '" + submatches[1].str() + "'");
|
||||
}
|
||||
|
||||
class AllowPathsFixture
|
||||
{
|
||||
protected:
|
||||
AllowPathsFixture():
|
||||
m_tempDir({"code/", "work/"}, TEST_CASE_NAME),
|
||||
m_tempWorkDir(m_tempDir.path() / "work"),
|
||||
m_codeDir(m_tempDir.path() / "code"),
|
||||
m_workDir(m_tempDir.path() / "work"),
|
||||
m_portablePrefix(("/" / boost::filesystem::canonical(m_codeDir).relative_path()).generic_string())
|
||||
{
|
||||
createFilesWithParentDirs(
|
||||
{
|
||||
m_codeDir / "a/b/c/d.sol",
|
||||
m_codeDir / "a/b/c.sol",
|
||||
m_codeDir / "a/b/X.sol",
|
||||
m_codeDir / "a/X/c.sol",
|
||||
m_codeDir / "X/b/c.sol",
|
||||
|
||||
m_codeDir / "a/bc/d.sol",
|
||||
m_codeDir / "X/bc/d.sol",
|
||||
|
||||
m_codeDir / "x/y/z.sol",
|
||||
m_codeDir / "contract.sol",
|
||||
|
||||
m_workDir / "a/b/c/d.sol",
|
||||
m_workDir / "a/b/c.sol",
|
||||
m_workDir / "a/b/X.sol",
|
||||
m_workDir / "a/X/c.sol",
|
||||
m_workDir / "X/b/c.sol",
|
||||
|
||||
m_workDir / "contract.sol",
|
||||
},
|
||||
"// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;"
|
||||
);
|
||||
|
||||
if (
|
||||
!createSymlinkIfSupportedByFilesystem("b", m_codeDir / "a/b_sym", true) ||
|
||||
!createSymlinkIfSupportedByFilesystem("../x/y", m_codeDir / "a/y_sym", true) ||
|
||||
!createSymlinkIfSupportedByFilesystem("../../a/b/c.sol", m_codeDir / "a/b/c_sym.sol", false) ||
|
||||
!createSymlinkIfSupportedByFilesystem("../../x/y/z.sol", m_codeDir / "a/b/z_sym.sol", false)
|
||||
)
|
||||
return;
|
||||
|
||||
m_caseSensitiveFilesystem = boost::filesystem::create_directories(m_codeDir / "A/B/C");
|
||||
soltestAssert(boost::filesystem::equivalent(m_codeDir / "a/b/c", m_codeDir / "A/B/C") != m_caseSensitiveFilesystem, "");
|
||||
}
|
||||
|
||||
TemporaryDirectory m_tempDir;
|
||||
TemporaryWorkingDirectory m_tempWorkDir;
|
||||
boost::filesystem::path const m_codeDir;
|
||||
boost::filesystem::path const m_workDir;
|
||||
string m_portablePrefix;
|
||||
bool m_caseSensitiveFilesystem = true;
|
||||
};
|
||||
|
||||
ostream& operator<<(ostream& _out, ImportCheck const& _value)
|
||||
{
|
||||
switch (_value.result)
|
||||
{
|
||||
case ImportCheck::Result::Unknown: _out << "Unknown"; break;
|
||||
case ImportCheck::Result::OK: _out << "OK"; break;
|
||||
case ImportCheck::Result::FileNotFound: _out << "FileNotFound"; break;
|
||||
case ImportCheck::Result::PathDisallowed: _out << "PathDisallowed"; break;
|
||||
}
|
||||
if (_value.message != "")
|
||||
_out << "(" << _value.message << ")";
|
||||
return _out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace boost::test_tools::tt_detail
|
||||
{
|
||||
|
||||
// Boost won't find the << operator unless we put it in the std namespace which is illegal.
|
||||
// The recommended solution is to overload print_log_value<> struct and make it use our operator.
|
||||
|
||||
template<>
|
||||
struct print_log_value<ImportCheck>
|
||||
{
|
||||
void operator()(std::ostream& _out, ImportCheck const& _value) { ::operator<<(_out, _value); }
|
||||
};
|
||||
|
||||
} // namespace boost::test_tools::tt_detail
|
||||
|
||||
namespace solidity::frontend::test
|
||||
{
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(CommandLineInterfaceAllowPathsTest)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_multiple_paths, AllowPathsFixture)
|
||||
{
|
||||
string allowedPaths =
|
||||
m_codeDir.generic_string() + "/a/b/X.sol," +
|
||||
m_codeDir.generic_string() + "/X/," +
|
||||
m_codeDir.generic_string() + "/z," +
|
||||
m_codeDir.generic_string() + "/a/b";
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", allowedPaths}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", allowedPaths}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", allowedPaths}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", allowedPaths}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPathsFixture)
|
||||
{
|
||||
string import = "import '" + m_portablePrefix + "/a/b/c.sol'";
|
||||
|
||||
// Without --allow-path
|
||||
BOOST_TEST(checkImport(import, {}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Absolute paths allowed
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string()}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol"}));
|
||||
|
||||
// Relative paths allowed
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b/c.sol"}));
|
||||
|
||||
// Non-normalized paths allowed
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/."}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/./"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/.."}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/./b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../a/b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a///b"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b//"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b///"}));
|
||||
|
||||
// Root path allowed
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=///"}));
|
||||
|
||||
// UNC paths should be treated differently from normal paths
|
||||
soltestAssert(FileReader::isUNCPath("/" + m_portablePrefix), "");
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=//"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/" + m_portablePrefix}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Paths going beyond root allowed
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/../../"}));
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/../.."}));
|
||||
#if !defined(_WIN32) || BOOST_VERSION > 107600
|
||||
// This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"}));
|
||||
#endif
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix}));
|
||||
|
||||
// File named like a directory
|
||||
BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol/"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture)
|
||||
{
|
||||
// Work dir is base path
|
||||
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", ""}));
|
||||
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y"}));
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", ""}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Work dir is not base path
|
||||
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}));
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture)
|
||||
{
|
||||
// Allowed paths are case-sensitive even on case-insensitive filesystems
|
||||
BOOST_TEST(
|
||||
checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", m_codeDir.string() + "/A/B/"}) ==
|
||||
ImportCheck::PathDisallowed()
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_import_forms, AllowPathsFixture)
|
||||
{
|
||||
// Absolute import paths
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a"}));
|
||||
|
||||
// Relative import paths
|
||||
// NOTE: Base path is whitelisted by default so we need the 'a/../../code/' part to get
|
||||
// outside of it. And it can't be just '../code/' because that would not be a direct import.
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import 'a/../../code/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/b/X.sol'", {"--allow-paths", "../code/a/b"}));
|
||||
|
||||
// Non-normalized relative import paths
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/./b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}));
|
||||
|
||||
// UNC paths in imports
|
||||
string uncImportPath = "/" + m_portablePrefix + "/a/b/c.sol";
|
||||
soltestAssert(FileReader::isUNCPath(uncImportPath), "");
|
||||
BOOST_TEST(checkImport("import '" + uncImportPath + "'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_input_files, AllowPathsFixture)
|
||||
{
|
||||
// By default none of the files is whitelisted
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Compiling a file whitelists its directory and subdirectories
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {m_codeDir.string() + "/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// If only file name is specified, its parent dir path is empty. This should be equivalent to
|
||||
// whitelisting the work dir.
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"contract.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'contract.sol'", {"contract.sol"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPathsFixture)
|
||||
{
|
||||
// Adding a remapping whitelists target's parent directory and subdirectories
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol/"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b=../code/X/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b=../code/X/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Adding a remapping whitelists the target and subdirectories when the target is a directory
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c/"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Adding a remapping whitelists target's parent directory and subdirectories when the target
|
||||
// is a directory but does not have a trailing slash
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c"}));
|
||||
|
||||
// Adding a remapping to a relative target at VFS root whitelists the work dir
|
||||
BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol", "--base-path=../code/a/b/"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Adding a remapping with an empty target does not whitelist anything
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Adding a remapping that includes .. or . segments whitelists the parent dir and subdirectories
|
||||
// of the resolved target
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// If the target is just a file name, its parent dir path is empty. This should be equivalent to
|
||||
// whitelisting the work dir.
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"x=contract.sol"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import 'contract.sol'", {"x=contract.sol"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_base_path, AllowPathsFixture)
|
||||
{
|
||||
// Relative base path whitelists its content
|
||||
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a"}));
|
||||
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a"}));
|
||||
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a"}));
|
||||
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a"}));
|
||||
|
||||
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a/"}));
|
||||
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a/"}));
|
||||
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a/"}));
|
||||
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a/"}));
|
||||
|
||||
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/."}));
|
||||
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/./"}));
|
||||
BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=.."}));
|
||||
BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=../"}));
|
||||
|
||||
// Absolute base path whitelists its content
|
||||
BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||
BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||
BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||
BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path", m_codeDir.string() + "/a"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFixture)
|
||||
{
|
||||
// Work dir is only automatically whitelisted if it matches base path
|
||||
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||
|
||||
// Compiling a file in the work dir whitelists it even if it's not in base path
|
||||
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "a/b/c.sol"}));
|
||||
|
||||
// Work dir can also be whitelisted manually
|
||||
BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "--allow-paths=."}));
|
||||
|
||||
// Not setting base path whitelists the working directory
|
||||
BOOST_TEST(checkImport("import 'a/b/c.sol'", {}));
|
||||
BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {}));
|
||||
BOOST_TEST(checkImport("import 'a/b/X.sol'", {}));
|
||||
BOOST_TEST(checkImport("import 'a/X/c.sol'", {}));
|
||||
|
||||
// Setting base path to an empty value whitelists the working directory
|
||||
BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path", ""}));
|
||||
BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {"--base-path", ""}));
|
||||
BOOST_TEST(checkImport("import 'a/b/X.sol'", {"--base-path", ""}));
|
||||
BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture)
|
||||
{
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym/"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_outside_whitelisted_dir, AllowPathsFixture)
|
||||
{
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/x/"}));
|
||||
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed());
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/b/z_sym.sol"}));
|
||||
BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/y/z.sol"}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // namespace solidity::frontend::test
|
@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
||||
|
||||
expectedOptions.input.addStdin = true;
|
||||
expectedOptions.input.basePath = "/home/user/";
|
||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"};
|
||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"};
|
||||
expectedOptions.input.ignoreMissingFiles = true;
|
||||
expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler);
|
||||
expectedOptions.output.dir = "/tmp/out";
|
||||
@ -307,7 +307,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
|
||||
};
|
||||
expectedOptions.input.addStdin = true;
|
||||
expectedOptions.input.basePath = "/home/user/";
|
||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"};
|
||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"};
|
||||
expectedOptions.input.ignoreMissingFiles = true;
|
||||
expectedOptions.output.overwriteFiles = true;
|
||||
expectedOptions.output.evmVersion = EVMVersion::spuriousDragon();
|
||||
|
@ -54,5 +54,22 @@ test::OptionsReaderAndMessages test::parseCommandLineAndReadInputFiles(
|
||||
if (success && _processInput)
|
||||
success = cli.processInput();
|
||||
|
||||
return {success, cli.options(), cli.fileReader(), cli.standardJsonInput(), sout.str(), serr.str()};
|
||||
return {
|
||||
success,
|
||||
cli.options(),
|
||||
cli.fileReader(),
|
||||
cli.standardJsonInput(),
|
||||
sout.str(),
|
||||
stripPreReleaseWarning(serr.str()),
|
||||
};
|
||||
}
|
||||
|
||||
string test::stripPreReleaseWarning(string const& _stderrContent)
|
||||
{
|
||||
static regex const preReleaseWarningRegex{
|
||||
R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)"
|
||||
R"((\n)?)"
|
||||
};
|
||||
|
||||
return regex_replace(_stderrContent, preReleaseWarningRegex, "");
|
||||
}
|
||||
|
@ -50,4 +50,6 @@ OptionsReaderAndMessages parseCommandLineAndReadInputFiles(
|
||||
bool _processInput = false
|
||||
);
|
||||
|
||||
std::string stripPreReleaseWarning(std::string const& _stderrContent);
|
||||
|
||||
} // namespace solidity::frontend::test
|
||||
|
Loading…
Reference in New Issue
Block a user