зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
4dc3af09dd
Коммит
78b0c91daf
|
@ -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 ¯o,
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче