From 2a07761fc6a09543d456e83f2411914c225e12d4 Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Tue, 18 Oct 2022 16:10:33 +0200 Subject: [PATCH] Check for import without pragma and add cmdline test --- libsolidity/analysis/DeclarationContainer.h | 2 +- libsolidity/analysis/SyntaxChecker.cpp | 6 ------ libsolidity/ast/AST.h | 13 +++++++++++-- libsolidity/interface/CompilerStack.cpp | 15 +++++++++++++++ libsolidity/parsing/Parser.cpp | 17 ++++++++++++++--- .../stdlib_import_without_pragma/args | 0 .../stdlib_import_without_pragma/err | 1 + .../stdlib_import_without_pragma/exit | 1 + .../stdlib_import_without_pragma/input.sol | 7 +++++++ 9 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 test/cmdlineTests/stdlib_import_without_pragma/args create mode 100644 test/cmdlineTests/stdlib_import_without_pragma/err create mode 100644 test/cmdlineTests/stdlib_import_without_pragma/exit create mode 100644 test/cmdlineTests/stdlib_import_without_pragma/input.sol diff --git a/libsolidity/analysis/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h index e4cc97d1a..84fc2f872 100644 --- a/libsolidity/analysis/DeclarationContainer.h +++ b/libsolidity/analysis/DeclarationContainer.h @@ -108,7 +108,7 @@ public: void populateHomonyms(std::back_insert_iterator _it) const; private: - /// Disables autoPopulateStdlib in _settinsg if "pragma stdlib" is active in m_selfNode. + /// Disables autoPopulateStdlib in _settings if "pragma stdlib" is active in m_selfNode. void updateSettingsBasedOnStdlibPragma(ResolvingSettings& _settings) const; ASTNode const* m_selfNode = nullptr; diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 19b42b9ae..9a0b0f96c 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -181,12 +181,6 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) else if (_pragma.literals()[0] == "stdlib") { solAssert(m_sourceUnit, ""); - if (m_evmVersion < EVMVersion::constantinople()) - m_errorReporter.syntaxError( - 6634_error, - _pragma.location(), - "\"pragma stdlib\" requires Constantinople EVM version at the minimum." - ); m_sourceUnit->annotation().useStdlib = true; } else diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 06575beec..2597f1db9 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -309,8 +309,13 @@ public: int64_t _id, SourceLocation const& _location, std::vector _tokens, - std::vector _literals - ): ASTNode(_id, _location), m_tokens(std::move(_tokens)), m_literals(std::move(_literals)) + std::vector _literals, + bool useStdLib = false + ): + ASTNode(_id, _location), + m_tokens(std::move(_tokens)), + m_literals(std::move(_literals)), + m_useStdLib(useStdLib) {} void accept(ASTVisitor& _visitor) override; @@ -319,12 +324,16 @@ public: std::vector const& tokens() const { return m_tokens; } std::vector const& literals() const { return m_literals; } + bool useStdLib() const { return m_useStdLib; } + private: /// Sequence of tokens following the "pragma" keyword. std::vector m_tokens; /// Sequence of literals following the "pragma" keyword. std::vector m_literals; + /// Indicates whether the standard library has been activated via this pragma + bool const m_useStdLib; }; /** diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 944142362..249781b09 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -84,6 +84,7 @@ #include #include +#include #include #include @@ -374,6 +375,20 @@ bool CompilerStack::parse() auto it = solidity::solstdlib::sources.find(import->path()); if (it != solidity::solstdlib::sources.end()) { + auto useStdLib = [&]() { + auto const pragmas = ASTNode::filteredNodes(source.ast->nodes()); + return ranges::any_of(pragmas, [](PragmaDirective const* pragma) { + return pragma->useStdLib(); + }); + }; + + if (!useStdLib()) + solThrow( + CompilerError, + "Given source file not found: " + import->path() + ". " + + "If you want to enable the standard library, you may do so with 'pragma stdlib;'." + ); + auto [name, content] = *it; m_sources[name].charStream = make_unique(content, name); sourcesToParse.push_back(name); diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index a9065b176..52b9f7080 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -210,6 +210,7 @@ ASTPointer Parser::parsePragmaDirective() expectToken(Token::Pragma); vector literals; vector tokens; + bool useStdLib = false; do { Token token = m_scanner->currentToken(); @@ -229,7 +230,18 @@ ASTPointer Parser::parsePragmaDirective() nodeFactory.markEndPosition(); expectToken(Token::Semicolon); - if (literals.size() >= 1 && literals[0] == "solidity") + if (!literals.empty() && literals[0] == "stdlib") + { + if (m_evmVersion < EVMVersion::constantinople()) + m_errorReporter.syntaxError( + 6634_error, + nodeFactory.location(), + "\"pragma stdlib\" requires Constantinople EVM version at the minimum." + ); + useStdLib = true; + } + + if (!literals.empty() && literals[0] == "solidity") { parsePragmaVersion( nodeFactory.location(), @@ -238,7 +250,7 @@ ASTPointer Parser::parsePragmaDirective() ); } - return nodeFactory.createNode(tokens, literals); + return nodeFactory.createNode(tokens, literals, useStdLib); } ASTPointer Parser::parseImportDirective() @@ -1118,7 +1130,6 @@ ASTPointer Parser::parseTypeName() unsigned secondSize; tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize); - ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); advance(); auto stateMutability = elemTypeName.token() == Token::Address diff --git a/test/cmdlineTests/stdlib_import_without_pragma/args b/test/cmdlineTests/stdlib_import_without_pragma/args new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/stdlib_import_without_pragma/err b/test/cmdlineTests/stdlib_import_without_pragma/err new file mode 100644 index 000000000..df4f732f9 --- /dev/null +++ b/test/cmdlineTests/stdlib_import_without_pragma/err @@ -0,0 +1 @@ +Error: Given source file not found: std/cryptography.sol. If you want to enable the standard library, you may do so with 'pragma stdlib;'. diff --git a/test/cmdlineTests/stdlib_import_without_pragma/exit b/test/cmdlineTests/stdlib_import_without_pragma/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/stdlib_import_without_pragma/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/stdlib_import_without_pragma/input.sol b/test/cmdlineTests/stdlib_import_without_pragma/input.sol new file mode 100644 index 000000000..1a33e417b --- /dev/null +++ b/test/cmdlineTests/stdlib_import_without_pragma/input.sol @@ -0,0 +1,7 @@ +import { ecrecover } from "std/cryptography.sol"; + +contract C { + function f(bytes32 h, uint8 v, bytes32 r, bytes32 s) public returns (address addr) { + return ecrecover(h, v, r, s); + } +} \ No newline at end of file