moc: Fix infinite recursion in macro substitution

When performing macro argument substitution, one should keep the set of
macro to exclude, else we can enter an infinite recursion.

Testcase:
 #define M1(A) A
 #define M2 M1(M2)

Task-number: QTBUG-29759
Change-Id: I564bbfed65e1c8599592eaf12c6d67285d2fd9ce
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
This commit is contained in:
Olivier Goffart 2013-02-19 16:56:30 +01:00 committed by The Qt Project
parent ec166aaa70
commit b05f19f232
5 changed files with 29 additions and 5 deletions

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the tools applications of the Qt Toolkit.
@ -536,12 +537,14 @@ static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode m
return symbols;
}
Symbols Preprocessor::macroExpand(Preprocessor *that, Symbols &toExpand, int &index, int lineNum, bool one)
Symbols Preprocessor::macroExpand(Preprocessor *that, Symbols &toExpand, int &index,
int lineNum, bool one, const QSet<QByteArray> &excludeSymbols)
{
SymbolStack symbols;
SafeSymbols sf;
sf.symbols = toExpand;
sf.index = index;
sf.excludedSymbols = excludeSymbols;
symbols.push(sf);
Symbols result;
@ -664,7 +667,7 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
if (i == macro.symbols.size() - 1 || macro.symbols.at(i + 1).token != PP_HASHHASH) {
Symbols arg = arguments.at(index);
int idx = 1;
expansion += macroExpand(that, arg, idx, lineNum, false);
expansion += macroExpand(that, arg, idx, lineNum, false, symbols.excludeSymbols());
} else {
expansion += arguments.at(index);
}

View File

@ -85,7 +85,8 @@ public:
void substituteUntilNewline(Symbols &substituted);
static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName);
static Symbols macroExpand(Preprocessor *that, Symbols &toExpand, int &index, int lineNum, bool one);
static Symbols macroExpand(Preprocessor *that, Symbols &toExpand, int &index, int lineNum, bool one,
const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
int evaluateCondition();

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the tools applications of the Qt Toolkit.
@ -134,6 +135,7 @@ typedef QVector<Symbol> Symbols;
struct SafeSymbols {
Symbols symbols;
QByteArray expandedMacro;
QSet<QByteArray> excludedSymbols;
int index;
};
@ -159,6 +161,7 @@ public:
inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); }
bool dontReplaceSymbol(const QByteArray &name);
QSet<QByteArray> excludeSymbols();
};
inline bool SymbolStack::test(Token token)
@ -178,12 +181,22 @@ inline bool SymbolStack::test(Token token)
inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name)
{
for (int i = 0; i < size(); ++i) {
if (name == at(i).expandedMacro)
if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name))
return true;
}
return false;
}
inline QSet<QByteArray> SymbolStack::excludeSymbols()
{
QSet<QByteArray> set;
for (int i = 0; i < size(); ++i) {
set << at(i).expandedMacro;
set += at(i).excludedSymbols;
}
return set;
}
QT_END_NAMESPACE
#endif // SYMBOLS_H

View File

@ -76,6 +76,9 @@
#endif
#define PD_ADD_SUFFIX(x) PD_DEFINE1(x,_SUFFIX)
#define PD_DEFINE_ITSELF PD_ADD_SUFFIX(PD_DEFINE_ITSELF)
PD_BEGIN_NAMESPACE
class PD_CLASSNAME : public QObject
@ -128,6 +131,8 @@ public slots:
void conditionSlot() {}
#endif
void PD_DEFINE_ITSELF(int) {}
};
#undef QString

View File

@ -2772,7 +2772,6 @@ void tst_Moc::parseDefines()
}
if (!qstrcmp(mci.name(), "TestString2")) {
++count;
qDebug() << mci.value();
QVERIFY(!qstrcmp(mci.value(), "ParseDefine"));
}
if (!qstrcmp(mci.name(), "TestString3")) {
@ -2781,6 +2780,9 @@ void tst_Moc::parseDefines()
}
}
QVERIFY(count == 3);
index = mo->indexOfSlot("PD_DEFINE_ITSELF_SUFFIX(int)");
QVERIFY(index != -1);
}
void tst_Moc::preprocessorOnly()