Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up the mess of basePath in solc #9353

Closed
wants to merge 1 commit into from
Closed

Clean up the mess of basePath in solc #9353

wants to merge 1 commit into from

Conversation

axic
Copy link
Member

@axic axic commented Jul 7, 2020

The goal of this PR is to make sure that with solc/solc --base-path openzeppelin-contracts/contracts/ openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol the following imports will work:

  • in openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol: import "./IERC20.sol";
  • in openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol: import "../../math/SafeMath.sol";

@@ -563,7 +563,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
addStdin = true;
else
{
auto infile = boost::filesystem::path(path);
auto const infile = m_basePath / path; //boost::filesystem::path(path);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes behaviour: if --base-path is specified, that will be prepended to the filename, e.g. there is no need to use a complete path.

Because of this it may be a breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds a bit weird to me - arguments to shell commands should always be files that can be resolved in the usual way.

Shouldn't we rather do something like:

if (absolute_path(m_basePath).isPrefixOf(absolute_path(path)))
  path = absolute_path(path).removePrefix(absolute_path(m_basePath))
infile = m_basePath / path;

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that can be a convenient feature, however couldn't find similar functions in boost to your pseudocode. Do you have any pointers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth maybe you missed this, but there are no such features in boost/std::fs. Did you mean to implement these and/or was this just pseudo code for logic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just pseudo code.

@@ -590,10 +590,13 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
continue;
}

m_sourceCodes[infile.generic_string()] = readFileAsString(infile.string());
m_sourceCodes[path] = readFileAsString(infile.string());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we ensure the source mapping in CompilerStack is not tainted with the value of --base-path. This is only a change because above we prepend m_basePath.

}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
if (!m_basePath.empty())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we also include the base path in the allowed directories.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See line 1115

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason it was not working for me without this.

}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
if (!m_basePath.empty())
m_allowedDirectories.push_back(boost::filesystem::canonical(m_basePath));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weakly canonical?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't you saying above we don't need this because line 1155 does it too?

@axic
Copy link
Member Author

axic commented Oct 30, 2020

Need to check if this could close #9346.

@chriseth
Copy link
Contributor

I am still of the opinion, that the commandline arguments to solc should be proper paths that the shell can resolve. Internally, it would be nice to strip the base path if the given file is inside that directory.

@axic
Copy link
Member Author

axic commented Nov 17, 2020

Just to state the problem, I expect the following to work:

$ solc/solc --base-path openzeppelin-contracts/contracts/ openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol 
Warning: This is a pre-release compiler version, please do not use it in production.

Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol

Error: Source "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol" not found: File outside of allowed directories.
 --> openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol:3:1:
  |
3 | import "./IERC20.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^

Error: Source "openzeppelin-contracts/contracts/math/SafeMath.sol" not found: File outside of allowed directories.
 --> openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol:4:1:
  |
4 | import "../../math/SafeMath.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Error: Source "openzeppelin-contracts/contracts/utils/Address.sol" not found: File outside of allowed directories.
 --> openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol:5:1:
  |
5 | import "../../utils/Address.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The above output is on develop, not this PR. Do we agree the above should work or not?

(And adding some of those extra paths to --allow-path does not help.)


I agree that file completion is good, and would be nice to have it. Disregarding that, this messy PR in its current form makes this to work:

$ solc/solc --base-path openzeppelin-contracts/contracts/ token/ERC20/SafeERC20.sol
Warning: This is a pre-release compiler version, please do not use it in production.

Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> token/ERC20/SafeERC20.sol

Error: Source file requires different compiler version (current compiler is 0.7.5-develop.2020.11.17+commit.0fe1791f.Darwin.appleclang) - note that nightly builds are considered to be strictly less than the released version
 --> math/SafeMath.sol:1:1:
  |
1 | pragma solidity ^0.6.0;
  | ^^^^^^^^^^^^^^^^^^^^^^^

Error: Source file requires different compiler version (current compiler is 0.7.5-develop.2020.11.17+commit.0fe1791f.Darwin.appleclang) - note that nightly builds are considered to be strictly less than the released version
 --> token/ERC20/IERC20.sol:1:1:
  |
1 | pragma solidity ^0.6.0;
  | ^^^^^^^^^^^^^^^^^^^^^^^

Error: Source file requires different compiler version (current compiler is 0.7.5-develop.2020.11.17+commit.0fe1791f.Darwin.appleclang) - note that nightly builds are considered to be strictly less than the released version
 --> utils/Address.sol:1:1:
  |
1 | pragma solidity ^0.6.0;
  | ^^^^^^^^^^^^^^^^^^^^^^^

@axic axic force-pushed the base-path branch 2 times, most recently from 98d1a9c to b678720 Compare November 20, 2020 00:59
@ethereum ethereum deleted a comment from stackenbotten Nov 20, 2020
@ethereum ethereum deleted a comment from stackenbotten Nov 20, 2020
@ethereum ethereum deleted a comment from stackenbotten Nov 20, 2020
@ethereum ethereum deleted a comment from stackenbotten Nov 20, 2020
@chriseth
Copy link
Contributor

Draft or ready for review?

@axic
Copy link
Member Author

axic commented Dec 14, 2020

For some reason now this translate solc test.sol into trying to load /test.sol.

@axic
Copy link
Member Author

axic commented Dec 14, 2020

Described what this should do on the top. Feel free to take over.

@chriseth
Copy link
Contributor

I think essentially solc --base-path BP BP/x should behave like cd BP; solc x - the main question is what to do if an input file lies outside the base path.

@cameel cameel added the takeover Can be taken over by someone other than label giver label Feb 3, 2021
bool CommandLineInterface::readInputFilesAndConfigureRemappings()
{
auto basePath = boost::filesystem::canonical(m_basePath);
if (!basePath.empty())
m_allowedDirectories.push_back(basePath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like m_allowedDirectories is a vector. I think we should make it a set to avoid duplicates (and the order does not matter, right?).

Comment on lines +622 to +623
if (isPrefix(basePath.string(), boost::filesystem::canonical(infile).string()))
path = removePrefix(basePath.string(), boost::filesystem::canonical(infile).string());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canonical() raises an exception if the path does not exist. I think this might be a problem here because infile might be a relative path that only works on top of basePath (rather than the current working directory).

if (m_basePath.empty())
infile = path;
else
infile = m_basePath / path;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs a check against path being an absolute path.

@cameel
Copy link
Member

cameel commented Feb 22, 2021

I could take this over.

What do you think about first adding a table in the docs that would illustrate how various combinations of --base-path, --allowed-paths and absolute/relative paths (both in imports and in paths specified on the command-line) interact with each other? This would show in a clear way how corner cases are handled now and we could then easily decide which ones do not match our expectations and change them.

We could also extract the path remapping logic out of CommandLineInterface and use these examples as test cases. Maybe also unify the behavior with standard JSON (do these options have equivalents there?).

@chriseth
Copy link
Contributor

Sounds good, but I think a summary of what we want and changing it right away is better than just documenting the status quo.

@axic
Copy link
Member Author

axic commented Mar 17, 2021

Closing this for now. We'll first figure out it in #11036 and #11105, and then come back.

@axic axic closed this Mar 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
takeover Can be taken over by someone other than label giver
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants