forked from qt-creator/qt-creator
[C++] Robustness fix for boost's preprocessor/seq/fold_right.hpp.
Change-Id: I11f6cff556519b768dd5d979dfd184809ed18291 Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
@@ -73,7 +73,8 @@
|
|||||||
namespace {
|
namespace {
|
||||||
enum {
|
enum {
|
||||||
eagerExpansion = 1,
|
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<PPToken> tokens;
|
std::list<PPToken> tokens;
|
||||||
const Macro *macro;
|
const Macro *macro;
|
||||||
TokenBuffer *next;
|
TokenBuffer *next;
|
||||||
QVector<QByteArray> blockedMacros;
|
|
||||||
|
|
||||||
template <typename _Iterator>
|
TokenBuffer(const PPToken *start, const PPToken *end, const Macro *macro, TokenBuffer *next)
|
||||||
TokenBuffer(_Iterator firstToken, _Iterator lastToken, const Macro *macro, TokenBuffer *next)
|
: tokens(start, end), macro(macro), next(next)
|
||||||
: tokens(firstToken, lastToken), 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)
|
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 true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockMacro(const QByteArray ¯oName)
|
|
||||||
{ blockedMacros.append(macroName); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
@@ -527,6 +526,7 @@ Preprocessor::State::State()
|
|||||||
, m_trueTest(MAX_LEVEL)
|
, m_trueTest(MAX_LEVEL)
|
||||||
, m_ifLevel(0)
|
, m_ifLevel(0)
|
||||||
, m_tokenBuffer(0)
|
, m_tokenBuffer(0)
|
||||||
|
, m_tokenBufferDepth(0)
|
||||||
, m_inPreprocessorDirective(false)
|
, m_inPreprocessorDirective(false)
|
||||||
, m_result(0)
|
, m_result(0)
|
||||||
, m_markGeneratedTokens(true)
|
, m_markGeneratedTokens(true)
|
||||||
@@ -538,6 +538,37 @@ Preprocessor::State::State()
|
|||||||
m_trueTest[m_ifLevel] = false;
|
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)
|
Preprocessor::Preprocessor(Client *client, Environment *env)
|
||||||
: m_client(client)
|
: m_client(client)
|
||||||
@@ -665,10 +696,7 @@ void Preprocessor::handleDefined(PPToken *tk)
|
|||||||
void Preprocessor::pushToken(Preprocessor::PPToken *tk)
|
void Preprocessor::pushToken(Preprocessor::PPToken *tk)
|
||||||
{
|
{
|
||||||
const PPToken currentTokenBuffer[] = { *tk };
|
const PPToken currentTokenBuffer[] = { *tk };
|
||||||
m_state.m_tokenBuffer = new TokenBuffer(currentTokenBuffer,
|
m_state.pushTokenBuffer(currentTokenBuffer, currentTokenBuffer + 1, 0);
|
||||||
currentTokenBuffer + 1,
|
|
||||||
/*macro */ 0,
|
|
||||||
m_state.m_tokenBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::lex(PPToken *tk)
|
void Preprocessor::lex(PPToken *tk)
|
||||||
@@ -676,9 +704,7 @@ void Preprocessor::lex(PPToken *tk)
|
|||||||
_Lagain:
|
_Lagain:
|
||||||
if (m_state.m_tokenBuffer) {
|
if (m_state.m_tokenBuffer) {
|
||||||
if (m_state.m_tokenBuffer->tokens.empty()) {
|
if (m_state.m_tokenBuffer->tokens.empty()) {
|
||||||
TokenBuffer *r = m_state.m_tokenBuffer;
|
m_state.popTokenBuffer();
|
||||||
m_state.m_tokenBuffer = m_state.m_tokenBuffer->next;
|
|
||||||
delete r;
|
|
||||||
goto _Lagain;
|
goto _Lagain;
|
||||||
}
|
}
|
||||||
*tk = m_state.m_tokenBuffer->tokens.front();
|
*tk = m_state.m_tokenBuffer->tokens.front();
|
||||||
@@ -767,12 +793,11 @@ bool Preprocessor::handleIdentifier(PPToken *tk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray macroName = macroNameRef.toByteArray();
|
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);
|
Macro *macro = m_env->resolve(macroName);
|
||||||
if (!macro)
|
if (!macro)
|
||||||
return false;
|
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;
|
// qDebug() << "expanding" << macro->name() << "on line" << tk->lineno;
|
||||||
|
|
||||||
if (m_client)
|
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.
|
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(),
|
m_state.pushTokenBuffer(body.begin(), body.end(), macro);
|
||||||
macro, m_state.m_tokenBuffer);
|
|
||||||
m_state.m_tokenBuffer->blockMacro(macroName);
|
|
||||||
|
|
||||||
if (m_client)
|
if (m_client)
|
||||||
m_client->stopExpandingMacro(tk->offset, *macro);
|
m_client->stopExpandingMacro(tk->offset, *macro);
|
||||||
|
@@ -98,6 +98,9 @@ private:
|
|||||||
struct State {
|
struct State {
|
||||||
State();
|
State();
|
||||||
|
|
||||||
|
void pushTokenBuffer(const PPToken *start, const PPToken *end, const Macro *macro);
|
||||||
|
void popTokenBuffer();
|
||||||
|
|
||||||
QString m_currentFileName;
|
QString m_currentFileName;
|
||||||
|
|
||||||
QByteArray m_source;
|
QByteArray m_source;
|
||||||
@@ -106,6 +109,7 @@ private:
|
|||||||
QBitArray m_trueTest;
|
QBitArray m_trueTest;
|
||||||
int m_ifLevel;
|
int m_ifLevel;
|
||||||
Internal::TokenBuffer *m_tokenBuffer;
|
Internal::TokenBuffer *m_tokenBuffer;
|
||||||
|
unsigned m_tokenBufferDepth;
|
||||||
bool m_inPreprocessorDirective;
|
bool m_inPreprocessorDirective;
|
||||||
|
|
||||||
QByteArray *m_result;
|
QByteArray *m_result;
|
||||||
|
Reference in New Issue
Block a user