diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp | 182 |
1 files changed, 116 insertions, 66 deletions
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp index 1116c516f..f38b39635 100644 --- a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp +++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/MacroExpander.cpp @@ -4,29 +4,34 @@ // found in the LICENSE file. // -#include "MacroExpander.h" +#include "compiler/preprocessor/MacroExpander.h" #include <algorithm> -#include <sstream> -#include "DiagnosticsBase.h" -#include "Token.h" +#include "common/debug.h" +#include "compiler/preprocessor/DiagnosticsBase.h" +#include "compiler/preprocessor/Token.h" namespace pp { +namespace +{ + +const size_t kMaxContextTokens = 10000; + class TokenLexer : public Lexer { public: typedef std::vector<Token> TokenVector; - TokenLexer(TokenVector* tokens) + TokenLexer(TokenVector *tokens) { tokens->swap(mTokens); mIter = mTokens.begin(); } - virtual void lex(Token* token) + void lex(Token *token) override { if (mIter == mTokens.end()) { @@ -40,30 +45,26 @@ class TokenLexer : public Lexer } private: - PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); - TokenVector mTokens; TokenVector::const_iterator mIter; }; -MacroExpander::MacroExpander(Lexer* lexer, - MacroSet* macroSet, - Diagnostics* diagnostics) : - mLexer(lexer), - mMacroSet(macroSet), - mDiagnostics(diagnostics) +} // anonymous namespace + +MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics) + : mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mTotalTokensInContexts(0) { } MacroExpander::~MacroExpander() { - for (std::size_t i = 0; i < mContextStack.size(); ++i) + for (MacroContext *context : mContextStack) { - delete mContextStack[i]; + delete context; } } -void MacroExpander::lex(Token* token) +void MacroExpander::lex(Token *token) { while (true) { @@ -97,7 +98,7 @@ void MacroExpander::lex(Token* token) } } -void MacroExpander::getToken(Token* token) +void MacroExpander::getToken(Token *token) { if (mReserveToken.get()) { @@ -118,21 +119,22 @@ void MacroExpander::getToken(Token* token) } else { + ASSERT(mTotalTokensInContexts == 0); mLexer->lex(token); } } -void MacroExpander::ungetToken(const Token& token) +void MacroExpander::ungetToken(const Token &token) { if (!mContextStack.empty()) { - MacroContext* context = mContextStack.back(); + MacroContext *context = mContextStack.back(); context->unget(); - assert(context->replacements[context->index] == token); + ASSERT(context->replacements[context->index] == token); } else { - assert(!mReserveToken.get()); + ASSERT(!mReserveToken.get()); mReserveToken.reset(new Token(token)); } } @@ -148,12 +150,14 @@ bool MacroExpander::isNextTokenLeftParen() return lparen; } -bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) +bool MacroExpander::pushMacro(const Macro ¯o, const Token &identifier) { - assert(!macro.disabled); - assert(!identifier.expansionDisabled()); - assert(identifier.type == Token::IDENTIFIER); - assert(identifier.text == macro.name); + ASSERT(!macro.disabled); + ASSERT(!identifier.expansionDisabled()); + ASSERT(identifier.type == Token::IDENTIFIER); + ASSERT(identifier.text == macro.name); + + macro.expansionCount++; std::vector<Token> replacements; if (!expandMacro(macro, identifier, &replacements)) @@ -162,31 +166,41 @@ bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) // Macro is disabled for expansion until it is popped off the stack. macro.disabled = true; - MacroContext* context = new MacroContext; + MacroContext *context = new MacroContext; context->macro = ¯o; context->replacements.swap(replacements); mContextStack.push_back(context); + mTotalTokensInContexts += context->replacements.size(); return true; } void MacroExpander::popMacro() { - assert(!mContextStack.empty()); + ASSERT(!mContextStack.empty()); - MacroContext* context = mContextStack.back(); + MacroContext *context = mContextStack.back(); mContextStack.pop_back(); - assert(context->empty()); - assert(context->macro->disabled); + ASSERT(context->empty()); + ASSERT(context->macro->disabled); + ASSERT(context->macro->expansionCount > 0); context->macro->disabled = false; + context->macro->expansionCount--; + mTotalTokensInContexts -= context->replacements.size(); delete context; } -bool MacroExpander::expandMacro(const Macro& macro, - const Token& identifier, - std::vector<Token>* replacements) +bool MacroExpander::expandMacro(const Macro ¯o, + const Token &identifier, + std::vector<Token> *replacements) { replacements->clear(); + + // In the case of an object-like macro, the replacement list gets its location + // from the identifier, but in the case of a function-like macro, the replacement + // list gets its location from the closing parenthesis of the macro invocation. + // This is tested by dEQP-GLES3.functional.shaders.preprocessor.predefined_macros.* + SourceLocation replacementLocation = identifier.location; if (macro.type == Macro::kTypeObj) { replacements->assign(macro.replacements.begin(), @@ -194,31 +208,27 @@ bool MacroExpander::expandMacro(const Macro& macro, if (macro.predefined) { - static const std::string kLine = "__LINE__"; - static const std::string kFile = "__FILE__"; + const char kLine[] = "__LINE__"; + const char kFile[] = "__FILE__"; - assert(replacements->size() == 1); + ASSERT(replacements->size() == 1); Token& repl = replacements->front(); if (macro.name == kLine) { - std::ostringstream stream; - stream << identifier.location.line; - repl.text = stream.str(); + repl.text = ToString(identifier.location.line); } else if (macro.name == kFile) { - std::ostringstream stream; - stream << identifier.location.file; - repl.text = stream.str(); + repl.text = ToString(identifier.location.file); } } } else { - assert(macro.type == Macro::kTypeFunc); + ASSERT(macro.type == Macro::kTypeFunc); std::vector<MacroArg> args; args.reserve(macro.parameters.size()); - if (!collectMacroArgs(macro, identifier, &args)) + if (!collectMacroArgs(macro, identifier, &args, &replacementLocation)) return false; replaceMacroParams(macro, args, replacements); @@ -234,27 +244,30 @@ bool MacroExpander::expandMacro(const Macro& macro, repl.setAtStartOfLine(identifier.atStartOfLine()); repl.setHasLeadingSpace(identifier.hasLeadingSpace()); } - repl.location = identifier.location; + repl.location = replacementLocation; } return true; } -bool MacroExpander::collectMacroArgs(const Macro& macro, - const Token& identifier, - std::vector<MacroArg>* args) +bool MacroExpander::collectMacroArgs(const Macro ¯o, + const Token &identifier, + std::vector<MacroArg> *args, + SourceLocation *closingParenthesisLocation) { Token token; getToken(&token); - assert(token.type == '('); + ASSERT(token.type == '('); args->push_back(MacroArg()); - for (int openParens = 1; openParens != 0; ) + + int openParens = 1; + while (openParens != 0) { getToken(&token); if (token.type == Token::LAST) { - mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION, + mDiagnostics->report(Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION, identifier.location, identifier.text); // Do not lose EOF token. ungetToken(token); @@ -271,12 +284,14 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, case ')': --openParens; isArg = openParens != 0; + *closingParenthesisLocation = token.location; break; case ',': // The individual arguments are separated by comma tokens, but // the comma tokens between matching inner parentheses do not // seperate arguments. - if (openParens == 1) args->push_back(MacroArg()); + if (openParens == 1) + args->push_back(MacroArg()); isArg = openParens != 1; break; default: @@ -285,14 +300,15 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, } if (isArg) { - MacroArg& arg = args->back(); + MacroArg &arg = args->back(); // Initial whitespace is not part of the argument. - if (arg.empty()) token.setHasLeadingSpace(false); + if (arg.empty()) + token.setHasLeadingSpace(false); arg.push_back(token); } } - const Macro::Parameters& params = macro.parameters; + const Macro::Parameters ¶ms = macro.parameters; // If there is only one empty argument, it is equivalent to no argument. if (params.empty() && (args->size() == 1) && args->front().empty()) { @@ -302,8 +318,8 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, if (args->size() != params.size()) { Diagnostics::ID id = args->size() < macro.parameters.size() ? - Diagnostics::MACRO_TOO_FEW_ARGS : - Diagnostics::MACRO_TOO_MANY_ARGS; + Diagnostics::PP_MACRO_TOO_FEW_ARGS : + Diagnostics::PP_MACRO_TOO_MANY_ARGS; mDiagnostics->report(id, identifier.location, identifier.text); return false; } @@ -311,9 +327,9 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, // Pre-expand each argument before substitution. // This step expands each argument individually before they are // inserted into the macro body. - for (std::size_t i = 0; i < args->size(); ++i) + size_t numTokens = 0; + for (auto &arg : *args) { - MacroArg& arg = args->at(i); TokenLexer lexer(&arg); MacroExpander expander(&lexer, mMacroSet, mDiagnostics); @@ -323,18 +339,32 @@ bool MacroExpander::collectMacroArgs(const Macro& macro, { arg.push_back(token); expander.lex(&token); + numTokens++; + if (numTokens + mTotalTokensInContexts > kMaxContextTokens) + { + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return false; + } } } return true; } -void MacroExpander::replaceMacroParams(const Macro& macro, - const std::vector<MacroArg>& args, - std::vector<Token>* replacements) +void MacroExpander::replaceMacroParams(const Macro ¯o, + const std::vector<MacroArg> &args, + std::vector<Token> *replacements) { for (std::size_t i = 0; i < macro.replacements.size(); ++i) { - const Token& repl = macro.replacements[i]; + if (!replacements->empty() && + replacements->size() + mTotalTokensInContexts > kMaxContextTokens) + { + const Token &token = replacements->back(); + mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text); + return; + } + + const Token &repl = macro.replacements[i]; if (repl.type != Token::IDENTIFIER) { replacements->push_back(repl); @@ -353,7 +383,7 @@ void MacroExpander::replaceMacroParams(const Macro& macro, } std::size_t iArg = std::distance(macro.parameters.begin(), iter); - const MacroArg& arg = args[iArg]; + const MacroArg &arg = args[iArg]; if (arg.empty()) { continue; @@ -366,5 +396,25 @@ void MacroExpander::replaceMacroParams(const Macro& macro, } } +MacroExpander::MacroContext::MacroContext() : macro(0), index(0) +{ +} + +bool MacroExpander::MacroContext::empty() const +{ + return index == replacements.size(); +} + +const Token &MacroExpander::MacroContext::get() +{ + return replacements[index++]; +} + +void MacroExpander::MacroContext::unget() +{ + ASSERT(index > 0); + --index; +} + } // namespace pp |