Fix infinite recursion in macro expansion

BUG=angleproject:1600
TEST=angle_unittests

Change-Id: I72bf81ec060f36255a0f13b132a4fd69b89672ff
Reviewed-on: https://chromium-review.googlesource.com/412744
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Olli Etuaho 2016-11-21 14:23:06 +00:00 коммит произвёл Commit Bot
Родитель 4dc3af09dd
Коммит 78b0c91daf
3 изменённых файлов: 65 добавлений и 2 удалений

Просмотреть файл

@ -51,13 +51,44 @@ class TokenLexer : public Lexer
} // anonymous namespace
class MacroExpander::ScopedMacroReenabler final : angle::NonCopyable
{
public:
ScopedMacroReenabler(MacroExpander *expander);
~ScopedMacroReenabler();
private:
MacroExpander *mExpander;
};
MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander)
: mExpander(expander)
{
mExpander->mDeferReenablingMacros = true;
}
MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler()
{
mExpander->mDeferReenablingMacros = false;
for (auto *macro : mExpander->mMacrosToReenable)
{
macro->disabled = false;
}
mExpander->mMacrosToReenable.clear();
}
MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics)
: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics), mTotalTokensInContexts(0)
: mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics),
mTotalTokensInContexts(0),
mDeferReenablingMacros(false)
{
}
MacroExpander::~MacroExpander()
{
ASSERT(mMacrosToReenable.empty());
for (MacroContext *context : mContextStack)
{
delete context;
@ -187,7 +218,14 @@ void MacroExpander::popMacro()
ASSERT(context->empty());
ASSERT(context->macro->disabled);
ASSERT(context->macro->expansionCount > 0);
context->macro->disabled = false;
if (mDeferReenablingMacros)
{
mMacrosToReenable.push_back(context->macro);
}
else
{
context->macro->disabled = false;
}
context->macro->expansionCount--;
mTotalTokensInContexts -= context->replacements.size();
delete context;
@ -263,6 +301,11 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
args->push_back(MacroArg());
// Defer reenabling macros until args collection is finished to avoid the possibility of
// infinite recursion. Otherwise infinite recursion might happen when expanding the args after
// macros have been popped from the context stack when parsing the args.
ScopedMacroReenabler deferReenablingMacros(this);
int openParens = 1;
while (openParens != 0)
{

Просмотреть файл

@ -67,6 +67,11 @@ class MacroExpander : public Lexer
std::unique_ptr<Token> mReserveToken;
std::vector<MacroContext *> mContextStack;
size_t mTotalTokensInContexts;
bool mDeferReenablingMacros;
std::vector<const Macro *> mMacrosToReenable;
class ScopedMacroReenabler;
};
} // namespace pp

Просмотреть файл

@ -971,3 +971,18 @@ TEST_F(DefineTest, UndefineInInvocationPreLParen)
preprocess(input, expected);
}
// The name of the macro "a" is inside an incomplete macro invocation of macro "m()" in its own
// expansion. This should not result in infinite recursion.
TEST_F(DefineTest, RecursiveMacroNameInsideIncompleteMacroInvocationInMacroExpansion)
{
const char *input =
"#define m(a)\n"
"#define a m((a)\n"
"a)\n";
const char *expected =
"\n"
"\n"
"\n";
preprocess(input, expected);
}