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>
diff --git a/src/compiler/preprocessor/MacroExpander.cpp b/src/compiler/preprocessor/MacroExpander.cpp
index 25dc741..11f677e 100644
--- a/src/compiler/preprocessor/MacroExpander.cpp
+++ b/src/compiler/preprocessor/MacroExpander.cpp
@@ -51,13 +51,44 @@
 
 }  // 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 @@
     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 @@
 
     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)
     {