From 2bd86662a39592bb95878e99b77af14be89a23b4 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Wed, 4 Sep 2024 16:56:43 +0200 Subject: [PATCH] Debug attributes get only parsed, if debug attribute cache was set. --- libyul/AsmParser.cpp | 27 ++++++++++--------- libyul/AsmParser.h | 7 ++--- libyul/ObjectParser.cpp | 2 +- libyul/ObjectParser.h | 8 +++--- libyul/YulStack.cpp | 2 +- libyul/YulStack.h | 8 ++++-- test/libyul/Common.cpp | 15 ++++++++--- test/libyul/Common.h | 6 +++-- test/libyul/Parser.cpp | 9 ++++--- test/libyul/SyntaxTest.cpp | 5 +++- test/libyul/SyntaxTest.h | 8 +++++- .../invalid/invalid_debug_merge.yul | 2 ++ .../invalid/invalid_debug_patch.yul | 2 ++ .../invalid_debug_patch_patch_object.yul | 2 ++ .../invalid/invalid_debug_set.yul | 2 ++ 15 files changed, 70 insertions(+), 35 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index f6df876dd3da..4eec48085779 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -62,7 +62,6 @@ std::optional toInt(std::string const& _value) langutil::DebugData::ConstPtr Parser::createDebugData() const { - solAssert(m_debugAttributeCache); switch (m_useSourceLocationFrom) { case UseSourceLocationFrom::Scanner: @@ -70,27 +69,27 @@ langutil::DebugData::ConstPtr Parser::createDebugData() const ParserBase::currentLocation(), ParserBase::currentLocation(), {}, - m_currentDebugAttributes.has_value() - ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) - : DebugData::Attributes({}) + m_debugAttributeCache + ? m_currentDebugAttributes.has_value() ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) : DebugData::Attributes({}) + : std::nullopt ); case UseSourceLocationFrom::LocationOverride: return DebugData::create( m_locationOverride, m_locationOverride, {}, - m_currentDebugAttributes.has_value() - ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) - : DebugData::Attributes({}) + m_debugAttributeCache + ? m_currentDebugAttributes.has_value() ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) : DebugData::Attributes({}) + : std::nullopt ); case UseSourceLocationFrom::Comments: return DebugData::create( ParserBase::currentLocation(), m_locationFromComment, m_astIDFromComment, - m_currentDebugAttributes.has_value() - ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) - : DebugData::Attributes({}) + m_debugAttributeCache + ? m_currentDebugAttributes.has_value() ? DebugData::Attributes({m_debugAttributeCache->set(*m_currentDebugAttributes)}) : DebugData::Attributes({}) + : std::nullopt ); } solAssert(false, ""); @@ -200,7 +199,7 @@ void Parser::fetchDebugDataFromComment() else break; } - else if (match[1] == "@debug.set") + else if (match[1] == "@debug.set" && m_debugAttributeCache) { if (auto parseResult = parseDebugDataAttributeOperationComment(match[1], commentLiteral, m_scanner->currentCommentLocation())) { @@ -211,7 +210,7 @@ void Parser::fetchDebugDataFromComment() else break; } - else if (match[1] == "@debug.merge") + else if (match[1] == "@debug.merge" && m_debugAttributeCache) { if (auto parseResult = parseDebugDataAttributeOperationComment(match[1], commentLiteral, m_scanner->currentCommentLocation())) { @@ -226,7 +225,7 @@ void Parser::fetchDebugDataFromComment() else break; } - else if (match[1] == "@debug.patch") + else if (match[1] == "@debug.patch" && m_debugAttributeCache) { if (auto parseResult = parseDebugDataAttributeOperationComment(match[1], commentLiteral, m_scanner->currentCommentLocation())) { @@ -251,6 +250,7 @@ std::optional>> Parser::parseDeb langutil::SourceLocation const& _location ) { + solAssert(m_debugAttributeCache, "debug attributes can only be used with valid debug attribute cache"); std::optional jsonData; try { @@ -278,6 +278,7 @@ std::optional>> Parser::parseDeb void Parser::applyDebugDataAttributePatch(Json const& _jsonPatch, langutil::SourceLocation const& _location) { + solAssert(m_debugAttributeCache, "debug attributes can only be used with valid debug attribute cache"); try { if (!m_currentDebugAttributes.has_value()) diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index e4a6b51bd9fe..85aae3641806 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -60,7 +61,7 @@ class Parser: public langutil::ParserBase langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, std::optional _locationOverride = {}, - DebugAttributeCache::Ptr debugAttributesCache = {} + DebugAttributeCache::Ptr _debugAttributesCache = {} ): ParserBase(_errorReporter), m_dialect(_dialect), @@ -70,7 +71,7 @@ class Parser: public langutil::ParserBase UseSourceLocationFrom::LocationOverride : UseSourceLocationFrom::Scanner }, - m_debugAttributeCache(debugAttributesCache == nullptr ? std::make_shared() : debugAttributesCache) + m_debugAttributeCache(std::move(_debugAttributesCache)) {} /// Constructs a Yul parser that is using the debug data @@ -89,7 +90,7 @@ class Parser: public langutil::ParserBase UseSourceLocationFrom::Comments : UseSourceLocationFrom::Scanner }, - m_debugAttributeCache(debugAttributesCache == nullptr ? std::make_shared() : debugAttributesCache) + m_debugAttributeCache(std::move(debugAttributesCache)) {} /// Parses an inline assembly block starting with `{` and ending with `}`. diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index 123dedcb483d..5e648737603d 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -171,7 +171,7 @@ std::optional ObjectParser::tryParseSourceNameMapping() const std::shared_ptr ObjectParser::parseBlock(std::optional _sourceNames) { - Parser parser(m_errorReporter, m_dialect, std::move(_sourceNames)); + Parser parser(m_errorReporter, m_dialect, std::move(_sourceNames), m_cache); auto ast = parser.parseInline(m_scanner); yulAssert(ast || m_errorReporter.hasErrors(), "Invalid block but no error!"); return ast; diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h index 1d7756f5ae71..833a21967534 100644 --- a/libyul/ObjectParser.h +++ b/libyul/ObjectParser.h @@ -21,8 +21,9 @@ #pragma once -#include #include +#include +#include #include #include @@ -45,8 +46,8 @@ namespace solidity::yul class ObjectParser: public langutil::ParserBase { public: - explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect): - ParserBase(_errorReporter), m_dialect(_dialect) {} + explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, Parser::DebugAttributeCache::Ptr _cache = {}): + ParserBase(_errorReporter), m_dialect(_dialect), m_cache(std::move(_cache)) {} /// Parses a Yul object. /// Falls back to code-only parsing if the source starts with `{`. @@ -66,6 +67,7 @@ class ObjectParser: public langutil::ParserBase void addNamedSubObject(Object& _container, std::string_view _name, std::shared_ptr _subObject); Dialect const& m_dialect; + Parser::DebugAttributeCache::Ptr m_cache; }; } diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index 68da91d988aa..6418e713ea1c 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -55,7 +55,7 @@ bool YulStack::parse(std::string const& _sourceName, std::string const& _source) { m_charStream = std::make_unique(_source, _sourceName); std::shared_ptr scanner = std::make_shared(*m_charStream); - m_parserResult = ObjectParser(m_errorReporter, languageToDialect(m_language, m_evmVersion)).parse(scanner, false); + m_parserResult = ObjectParser(m_errorReporter, languageToDialect(m_language, m_evmVersion), m_cache).parse(scanner, false); } catch (UnimplementedFeatureError const& _error) { diff --git a/libyul/YulStack.h b/libyul/YulStack.h index f0487ffe52cb..e9caae1b42c5 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -37,6 +37,7 @@ #include #include +#include namespace solidity::evmasm { @@ -91,7 +92,8 @@ class YulStack: public langutil::CharStreamProvider Language _language, solidity::frontend::OptimiserSettings _optimiserSettings, langutil::DebugInfoSelection const& _debugInfoSelection, - std::shared_ptr _objectOptimizer = nullptr + std::shared_ptr _objectOptimizer = nullptr, + Parser::DebugAttributeCache::Ptr _cache = {} ): m_language(_language), m_evmVersion(_evmVersion), @@ -99,7 +101,8 @@ class YulStack: public langutil::CharStreamProvider m_optimiserSettings(std::move(_optimiserSettings)), m_debugInfoSelection(_debugInfoSelection), m_errorReporter(m_errors), - m_objectOptimizer(_objectOptimizer ? std::move(_objectOptimizer) : std::make_shared()) + m_objectOptimizer(_objectOptimizer ? std::move(_objectOptimizer) : std::make_shared()), + m_cache(std::move(_cache)) {} /// @returns the char stream used during parsing @@ -177,6 +180,7 @@ class YulStack: public langutil::CharStreamProvider langutil::ErrorReporter m_errorReporter; std::shared_ptr m_objectOptimizer; + Parser::DebugAttributeCache::Ptr m_cache; }; } diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index d365280b84fd..57dc3387b880 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -19,6 +19,9 @@ * Common functions the Yul tests. */ +#include "libyul/AsmParser.h" + + #include #include @@ -36,6 +39,7 @@ #include +#include #include using namespace solidity; @@ -50,7 +54,7 @@ Dialect const& defaultDialect() } } -std::pair, std::shared_ptr> yul::test::parse(std::string const& _source) +std::pair, std::shared_ptr> yul::test::parse(std::string const& _source, Parser::DebugAttributeCache::Ptr _cache) { YulStack stack( solidity::test::CommonOptions::get().evmVersion(), @@ -59,7 +63,9 @@ std::pair, std::shared_ptr> yul solidity::test::CommonOptions::get().optimize ? solidity::frontend::OptimiserSettings::standard() : solidity::frontend::OptimiserSettings::minimal(), - DebugInfoSelection::ExceptExperimental() + DebugInfoSelection::ExceptExperimental(), + nullptr, + std::move(_cache) ); if (!stack.parseAndAnalyze("", _source) || !stack.errors().empty()) BOOST_FAIL("Invalid source."); @@ -69,13 +75,14 @@ std::pair, std::shared_ptr> yul std::pair, std::shared_ptr> yul::test::parse( std::string const& _source, Dialect const& _dialect, - ErrorList& _errors + ErrorList& _errors, + Parser::DebugAttributeCache::Ptr _cache ) { ErrorReporter errorReporter(_errors); CharStream stream(_source, ""); std::shared_ptr scanner = std::make_shared(stream); - std::shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); + std::shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect, std::move(_cache)).parse(scanner, false); if (!parserResult) return {}; if (!parserResult->hasCode() || errorReporter.hasErrors()) diff --git a/test/libyul/Common.h b/test/libyul/Common.h index c87f1c68be17..35504c45afe9 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -46,10 +48,10 @@ namespace solidity::yul::test { std::pair, std::shared_ptr> -parse(std::string const& _source); +parse(std::string const& _source, Parser::DebugAttributeCache::Ptr _cache = {}); std::pair, std::shared_ptr> -parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors); +parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors, Parser::DebugAttributeCache::Ptr _cache = {}); Block disambiguate(std::string const& _source); std::string format(std::string const& _source); diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 5636047dc3c7..85e5e582fac8 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -1007,7 +1007,8 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_attributes_empty) auto const sourceText = R"( {} )"; - EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + auto const& dialect = EVMDialect::strictAssemblyForEVM(EVMVersion{}); + BOOST_REQUIRE(cache->cache().size() == 0); std::shared_ptr result = parse(sourceText, dialect, reporter, cache); BOOST_REQUIRE(cache->cache().size() == 0); } @@ -1021,7 +1022,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_attributes_set_empty) /// @debug.set {} {} )"; - EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + auto const& dialect = EVMDialect::strictAssemblyForEVM(EVMVersion{}); std::shared_ptr result = parse(sourceText, dialect, reporter, cache); BOOST_REQUIRE(cache->cache().size() == 1); } @@ -1036,7 +1037,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_attributes_set) /// @debug.set {"hello": "world"} {} )"; - EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + auto const& dialect = EVMDialect::strictAssemblyForEVM(EVMVersion{}); std::shared_ptr result = parse(sourceText, dialect, reporter, cache); BOOST_REQUIRE(cache->cache().size() == 1); } @@ -1055,7 +1056,7 @@ BOOST_AUTO_TEST_CASE(ethdebug_debug_attributes_multiple_set) {} } )"; - EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + auto const& dialect = EVMDialect::strictAssemblyForEVM(EVMVersion{}); std::shared_ptr result = parse(sourceText, dialect, reporter, cache); BOOST_REQUIRE(cache->cache().size() == 2); } diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index 7ed87bee450a..52cda2d2a07c 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -46,8 +46,10 @@ void SyntaxTest::parseAndAnalyze() ErrorList errorList{}; soltestAssert(m_dialect, ""); + if (m_debugAttributesEnabled && m_debugAttributesCache == nullptr) + m_debugAttributesCache = std::make_shared(); // Silently ignoring the results. - yul::test::parse(source, *m_dialect, errorList); + yul::test::parse(source, *m_dialect, errorList, m_debugAttributesCache); for (auto const& error: errorList) { int locationStart = -1; @@ -75,5 +77,6 @@ SyntaxTest::SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVe CommonSyntaxTest(_filename, _evmVersion) { std::string dialectName = m_reader.stringSetting("dialect", "evm"); + m_debugAttributesEnabled = m_reader.boolSetting("enableDebugAttributes", false); m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); } diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h index 27e59ee61439..6591140f6f29 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -18,8 +18,12 @@ #pragma once -#include +#include "libyul/AsmParser.h" +#include "libyul/optimiser/SimplificationRules.h" + + #include +#include namespace solidity::yul::test { @@ -40,6 +44,8 @@ class SyntaxTest: public solidity::test::CommonSyntaxTest private: Dialect const* m_dialect = nullptr; + bool m_debugAttributesEnabled = false; + Parser::DebugAttributeCache::Ptr m_debugAttributesCache; }; } diff --git a/test/libyul/yulSyntaxTests/invalid/invalid_debug_merge.yul b/test/libyul/yulSyntaxTests/invalid/invalid_debug_merge.yul index 13200b008cb8..f492d990d7a1 100644 --- a/test/libyul/yulSyntaxTests/invalid/invalid_debug_merge.yul +++ b/test/libyul/yulSyntaxTests/invalid/invalid_debug_merge.yul @@ -3,5 +3,7 @@ object "object" { /// @debug.merge {"HELLO": 2 } } +// ==== +// enableDebugAttributes: true // ---- // SyntaxError 5721: (37-65): @debug.merge: Could not parse debug data: parse error at line 1, column 12: syntax error while parsing object - unexpected end of input; expected '}' diff --git a/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch.yul b/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch.yul index 3f1d15e962da..ade80e757c22 100644 --- a/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch.yul +++ b/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch.yul @@ -3,5 +3,7 @@ object "object" { /// @debug.patch {"HELLO": invalid } } +// ==== +// enableDebugAttributes: true // ---- // SyntaxError 5721: (37-71): @debug.patch: Could not parse debug data: parse error at line 1, column 11: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal diff --git a/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch_patch_object.yul b/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch_patch_object.yul index a5c02823f27c..bf3abccea470 100644 --- a/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch_patch_object.yul +++ b/test/libyul/yulSyntaxTests/invalid/invalid_debug_patch_patch_object.yul @@ -3,5 +3,7 @@ object "object" { /// @debug.patch { "op": "unknown_operation", "path": "/variable_a", "value": ["test"] } } } +// ==== +// enableDebugAttributes: true // ---- // SyntaxError 9426: (37-125): @debug.patch: Could not patch debug data: parse error: operation value 'unknown_operation' is invalid diff --git a/test/libyul/yulSyntaxTests/invalid/invalid_debug_set.yul b/test/libyul/yulSyntaxTests/invalid/invalid_debug_set.yul index 3c99b7cb52bd..f81ec22fc2de 100644 --- a/test/libyul/yulSyntaxTests/invalid/invalid_debug_set.yul +++ b/test/libyul/yulSyntaxTests/invalid/invalid_debug_set.yul @@ -3,5 +3,7 @@ object "object" { /// @debug.set {"HELLO": "WORLD } } +// ==== +// enableDebugAttributes: true // ---- // SyntaxError 5721: (37-68): @debug.set: Could not parse debug data: parse error at line 1, column 17: syntax error while parsing value - invalid string: missing closing quote; last read: '"WORLD'