From f5aacb89ebf3ac658339a9befb14f616b22764c7 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 30 Mar 2012 14:21:22 +0200 Subject: [PATCH] [C++] Robustness fix for boost's preprocessor/seq/fold_right.hpp. Change-Id: I11f6cff556519b768dd5d979dfd184809ed18291 Reviewed-by: Roberto Raggi --- src/libs/cplusplus/pp-engine.cpp | 69 +++++++++++++++++++++----------- src/libs/cplusplus/pp-engine.h | 4 ++ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index d9897741ba5..e8c425e284f 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -73,7 +73,8 @@ namespace { enum { eagerExpansion = 1, - MAX_TOKEN_EXPANSION_COUNT = 5000 + MAX_TOKEN_EXPANSION_COUNT = 5000, + MAX_TOKEN_BUFFER_DEPTH = 16000, // for when macros are using some kind of right-folding, this is the list of "delayed" buffers waiting to be expanded after the current one. }; } @@ -109,22 +110,20 @@ struct TokenBuffer std::list tokens; const Macro *macro; TokenBuffer *next; - QVector blockedMacros; - template - TokenBuffer(_Iterator firstToken, _Iterator lastToken, const Macro *macro, TokenBuffer *next) - : tokens(firstToken, lastToken), macro(macro), next(next) + TokenBuffer(const PPToken *start, const PPToken *end, const Macro *macro, TokenBuffer *next) + : tokens(start, end), macro(macro), next(next) {} - bool isBlocked(const QByteArray ¯oName) const { + bool isBlocked(const Macro *macro) const { + if (!macro) + return false; + for (const TokenBuffer *it = this; it; it = it->next) - if (it->blockedMacros.contains(macroName)) + if (it->macro == macro && it->macro->name() == macro->name()) return true; return false; } - - void blockMacro(const QByteArray ¯oName) - { blockedMacros.append(macroName); } }; struct Value @@ -527,6 +526,7 @@ Preprocessor::State::State() , m_trueTest(MAX_LEVEL) , m_ifLevel(0) , m_tokenBuffer(0) + , m_tokenBufferDepth(0) , m_inPreprocessorDirective(false) , m_result(0) , m_markGeneratedTokens(true) @@ -538,6 +538,37 @@ Preprocessor::State::State() m_trueTest[m_ifLevel] = false; } +void Preprocessor::State::pushTokenBuffer(const PPToken *start, const PPToken *end, const Macro *macro) +{ + if (m_tokenBufferDepth <= MAX_TOKEN_BUFFER_DEPTH) { +#ifdef COMPRESS_TOKEN_BUFFER + // This does not work correctly for boost's preprocessor library, or that library exposes a bug in the code. + if (macro || !m_tokenBuffer) { + m_tokenBuffer = new TokenBuffer(start, end, macro, m_tokenBuffer); + ++m_tokenBufferDepth; + } else { + m_tokenBuffer->tokens.insert(m_tokenBuffer->tokens.begin(), start, end); + } +// qDebug()<<"New depth:" << m_tokenBufferDepth << "with buffer size:" << m_tokenBuffer->tokens.size(); +#else + m_tokenBuffer = new TokenBuffer(start, end, macro, m_tokenBuffer); + ++m_tokenBufferDepth; +#endif + } else { + //### Should we tell the user that his source is insane? +// qDebug() << "Macro insanity level reached in" << m_currentFileName; + } +} + +void Preprocessor::State::popTokenBuffer() +{ + TokenBuffer *r = m_tokenBuffer; + m_tokenBuffer = m_tokenBuffer->next; + delete r; + + if (m_tokenBufferDepth) + --m_tokenBufferDepth; +} Preprocessor::Preprocessor(Client *client, Environment *env) : m_client(client) @@ -665,10 +696,7 @@ void Preprocessor::handleDefined(PPToken *tk) void Preprocessor::pushToken(Preprocessor::PPToken *tk) { const PPToken currentTokenBuffer[] = { *tk }; - m_state.m_tokenBuffer = new TokenBuffer(currentTokenBuffer, - currentTokenBuffer + 1, - /*macro */ 0, - m_state.m_tokenBuffer); + m_state.pushTokenBuffer(currentTokenBuffer, currentTokenBuffer + 1, 0); } void Preprocessor::lex(PPToken *tk) @@ -676,9 +704,7 @@ void Preprocessor::lex(PPToken *tk) _Lagain: if (m_state.m_tokenBuffer) { if (m_state.m_tokenBuffer->tokens.empty()) { - TokenBuffer *r = m_state.m_tokenBuffer; - m_state.m_tokenBuffer = m_state.m_tokenBuffer->next; - delete r; + m_state.popTokenBuffer(); goto _Lagain; } *tk = m_state.m_tokenBuffer->tokens.front(); @@ -767,12 +793,11 @@ bool Preprocessor::handleIdentifier(PPToken *tk) } const QByteArray macroName = macroNameRef.toByteArray(); - if (tk->generated() && m_state.m_tokenBuffer && m_state.m_tokenBuffer->isBlocked(macroName)) - return false; - Macro *macro = m_env->resolve(macroName); if (!macro) return false; + if (tk->generated() && m_state.m_tokenBuffer && m_state.m_tokenBuffer->isBlocked(macro)) + return false; // qDebug() << "expanding" << macro->name() << "on line" << tk->lineno; if (m_client) @@ -802,9 +827,7 @@ bool Preprocessor::handleIdentifier(PPToken *tk) firstNewTk.f.whitespace = true; // the macro call is removed, so space the first token correctly. } - m_state.m_tokenBuffer = new TokenBuffer(body.begin(), body.end(), - macro, m_state.m_tokenBuffer); - m_state.m_tokenBuffer->blockMacro(macroName); + m_state.pushTokenBuffer(body.begin(), body.end(), macro); if (m_client) m_client->stopExpandingMacro(tk->offset, *macro); diff --git a/src/libs/cplusplus/pp-engine.h b/src/libs/cplusplus/pp-engine.h index 406f5a50a27..67fa9e11414 100644 --- a/src/libs/cplusplus/pp-engine.h +++ b/src/libs/cplusplus/pp-engine.h @@ -98,6 +98,9 @@ private: struct State { State(); + void pushTokenBuffer(const PPToken *start, const PPToken *end, const Macro *macro); + void popTokenBuffer(); + QString m_currentFileName; QByteArray m_source; @@ -106,6 +109,7 @@ private: QBitArray m_trueTest; int m_ifLevel; Internal::TokenBuffer *m_tokenBuffer; + unsigned m_tokenBufferDepth; bool m_inPreprocessorDirective; QByteArray *m_result;