diff --git a/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp b/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp index 65d6e0ab..b90f48cd 100644 --- a/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp +++ b/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp @@ -26,7 +26,7 @@ DefinesStreamProxy::Define::Define(std::string name, std::string value) { } -std::string DefinesStreamProxy::Define::Render(std::vector& parameterValues) +std::string DefinesStreamProxy::Define::Render(const std::vector& parameterValues) { if (parameterValues.empty() || m_parameter_positions.empty()) return m_value; @@ -52,7 +52,7 @@ std::string DefinesStreamProxy::Define::Render(std::vector& paramet return str.str(); } -void DefinesStreamProxy::Define::IdentifyParameters(std::vector& parameterNames) +void DefinesStreamProxy::Define::IdentifyParameters(const std::vector& parameterNames) { if (parameterNames.empty()) return; @@ -168,7 +168,7 @@ bool DefinesStreamProxy::MatchDefineDirective(const ParserLine& line, unsigned d const auto name = line.m_line.substr(nameStartPos, directivePosition - nameStartPos); - auto parameters = MatchDefineParameters(line, directivePosition); + const auto parameters = MatchDefineParameters(line, directivePosition); std::string value; if (directivePosition < line.m_line.size()) @@ -346,77 +346,88 @@ void DefinesStreamProxy::ExtractParametersFromDefineUsage(const ParserLine& line void DefinesStreamProxy::ExpandDefines(ParserLine& line) { - auto wordStart = 0u; - auto lastWordEnd = 0u; - auto inWord = false; - Define* value; + bool usesDefines; + auto defineIterations = 0u; - std::ostringstream str; - auto usesDefines = false; - - for (auto i = 0u; i < line.m_line.size(); i++) + do { - const auto c = line.m_line[i]; - if (!inWord) + if (defineIterations > MAX_DEFINE_ITERATIONS) + throw ParsingException(CreatePos(line, 1), "Potential define loop? Exceeded max define iterations of " + std::to_string(MAX_DEFINE_ITERATIONS) + " iterations."); + + usesDefines = false; + + auto wordStart = 0u; + auto lastWordEnd = 0u; + auto inWord = false; + Define* value; + std::ostringstream str; + + for (auto i = 0u; i < line.m_line.size(); i++) { - if (isalpha(c) || c == '_') + const auto c = line.m_line[i]; + if (!inWord) { - wordStart = i; - inWord = true; - } - } - else - { - if (!isalnum(c) && c != '_') - { - if (FindDefineForWord(line, wordStart, i, value)) + if (isalpha(c) || c == '_') { - std::vector parameterValues; - ExtractParametersFromDefineUsage(line, i, i, parameterValues); - const auto defineValue = value->Render(parameterValues); - - if (!usesDefines) - { - str << std::string(line.m_line, 0, wordStart) << defineValue; - usesDefines = true; - } - else - { - str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue; - } - lastWordEnd = i; + wordStart = i; + inWord = true; } - inWord = false; - } - } - } - - if (inWord) - { - if (FindDefineForWord(line, wordStart, line.m_line.size(), value)) - { - std::vector parameterValues; - const auto defineValue = value->Render(parameterValues); - - if (!usesDefines) - { - str << std::string(line.m_line, 0, wordStart) << defineValue; - usesDefines = true; } else { - str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue; - } - lastWordEnd = line.m_line.size(); - } - } + if (!isalnum(c) && c != '_') + { + if (FindDefineForWord(line, wordStart, i, value)) + { + std::vector parameterValues; + ExtractParametersFromDefineUsage(line, i, i, parameterValues); + const auto defineValue = value->Render(parameterValues); - if (usesDefines) - { - if (lastWordEnd < line.m_line.size()) - str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd); - line.m_line = str.str(); - } + if (!usesDefines) + { + str << std::string(line.m_line, 0, wordStart) << defineValue; + usesDefines = true; + } + else + { + str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue; + } + lastWordEnd = i; + } + inWord = false; + } + } + } + + if (inWord) + { + if (FindDefineForWord(line, wordStart, line.m_line.size(), value)) + { + const std::vector parameterValues; + const auto defineValue = value->Render(parameterValues); + + if (!usesDefines) + { + str << std::string(line.m_line, 0, wordStart) << defineValue; + usesDefines = true; + } + else + { + str << std::string(line.m_line, lastWordEnd, wordStart - lastWordEnd) << defineValue; + } + lastWordEnd = line.m_line.size(); + } + } + + if (usesDefines) + { + if (lastWordEnd < line.m_line.size()) + str << std::string(line.m_line, lastWordEnd, line.m_line.size() - lastWordEnd); + line.m_line = str.str(); + } + + defineIterations++; + } while (usesDefines); } void DefinesStreamProxy::AddDefine(Define define) diff --git a/src/Parser/Parsing/Impl/DefinesStreamProxy.h b/src/Parser/Parsing/Impl/DefinesStreamProxy.h index 961366ae..307d6c07 100644 --- a/src/Parser/Parsing/Impl/DefinesStreamProxy.h +++ b/src/Parser/Parsing/Impl/DefinesStreamProxy.h @@ -15,6 +15,8 @@ class DefinesStreamProxy final : public AbstractDirectiveStreamProxy static constexpr const char* ELSE_DIRECTIVE = "else"; static constexpr const char* ENDIF_DIRECTIVE = "endif"; + static constexpr auto MAX_DEFINE_ITERATIONS = 128u; + public: class DefineParameterPosition { @@ -35,8 +37,8 @@ public: Define(); Define(std::string name, std::string value); - void IdentifyParameters(std::vector& parameterNames); - std::string Render(std::vector& parameterValues); + void IdentifyParameters(const std::vector& parameterNames); + std::string Render(const std::vector& parameterValues); }; private: @@ -44,16 +46,16 @@ private: std::unordered_map m_defines; std::stack m_modes; unsigned m_ignore_depth; - - std::vector MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition); + + static std::vector MatchDefineParameters(const ParserLine& line, unsigned& parameterPosition); _NODISCARD bool MatchDefineDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchUndefDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchIfdefDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchElseDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchEndifDirective(const ParserLine& line, unsigned directivePosition); _NODISCARD bool MatchDirectives(const ParserLine& line); - - void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector& parameterValues); + + static void ExtractParametersFromDefineUsage(const ParserLine& line, unsigned parameterStart, unsigned& parameterEnd, std::vector& parameterValues); bool FindDefineForWord(const ParserLine& line, unsigned wordStart, unsigned wordEnd, Define*& value); void ExpandDefines(ParserLine& line);