[clang] [Clang][Parser] Avoid stack overflow in ParseExpressionList and ParseBlockLiteralExpression (#121952) (PR #235488)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 09:56:16 PDT 2026


https://github.com/rishit53 updated https://github.com/llvm/llvm-project/pull/235488

>From ec89448ab67d20a38081ad4aeae81482b2d042fa Mon Sep 17 00:00:00 2001
From: ptanhi611 <rishitmittal837 at gmail.com>
Date: Sun, 25 Oct 2026 21:59:41 +0530
Subject: [PATCH] [Clang][Parser] Avoid stack overflow in ParseExpressionList
 and ParseBlockLiteralExpression (#121952)

---
 clang/docs/ReleaseNotes.md    |  1 +
 clang/lib/Parse/ParseExpr.cpp | 92 +++++++++++++++++++----------------
 2 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 44f30666457f94..8a9756d9d41cea 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1156,6 +1156,7 @@ documentation](CIR/index.md) for more information regarding ClangIR's status and
   evaluated once in Sema and the results are stored in the AST. (#GH212106)
 - Fixed an assertion failure in `-extract-api` when a documentation comment
   contains invalid UTF-8. (#GH212393)
+- Fixed a stack overflow crash when parsing deeply nested expression lists and block literals. (#GH121952)
 - Fixed a crash in codegen on 32-bit targets caused by a struct too large to
   represent in `size_t`. The `err_struct_too_large` check now scales the
   threshold to the target's `size_t` width instead of using a fixed
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index d42ffc2ccf0a65..e0864f59aa8356 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3214,54 +3214,57 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
                                  bool FailImmediatelyOnInvalidExpr,
                                  bool ParsingExpansionStmtInitList) {
   bool SawError = false;
-  while (true) {
-    if (ExpressionStarts)
-      ExpressionStarts();
 
-    ExprResult Expr;
-    if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
-      Diag(Tok, diag::compat_cxx11_generalized_initializer_lists);
-      Expr = ParseBraceInitializer();
-    } else
-      Expr = ParseAssignmentExpression();
-
-    if (Tok.is(tok::ellipsis))
-      Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
-    else if (Tok.is(tok::code_completion)) {
-      // There's nothing to suggest in here as we parsed a full expression.
-      // Instead fail and propagate the error since caller might have something
-      // the suggest, e.g. signature help in function call. Note that this is
-      // performed before pushing the \p Expr, so that signature help can report
-      // current argument correctly.
-      SawError = true;
-      cutOffParsing();
-      break;
-    }
-    if (Expr.isInvalid()) {
-      SawError = true;
-      if (FailImmediatelyOnInvalidExpr)
+  Actions.runWithSufficientStackSpace(Tok.getLocation(), [&] {
+    while (true) {
+      if (ExpressionStarts)
+        ExpressionStarts();
+
+      ExprResult Expr;
+      if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+        Diag(Tok, diag::compat_cxx11_generalized_initializer_lists);
+        Expr = ParseBraceInitializer();
+      } else
+        Expr = ParseAssignmentExpression();
+
+      if (Tok.is(tok::ellipsis))
+        Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
+      else if (Tok.is(tok::code_completion)) {
+        // There's nothing to suggest in here as we parsed a full expression.
+        // Instead fail and propagate the error since caller might have
+        // something the suggest, e.g. signature help in function call. Note
+        // that this is performed before pushing the \p Expr, so that signature
+        // help can report current argument correctly.
+        SawError = true;
+        cutOffParsing();
         break;
+      }
+      if (Expr.isInvalid()) {
+        SawError = true;
+        if (FailImmediatelyOnInvalidExpr)
+          break;
 
-      // We expect '}' rather than ')' at the end of an expansion-init-list.
-      SkipUntil(tok::comma,
-                ParsingExpansionStmtInitList ? tok::r_brace : tok::r_paren,
-                StopAtSemi | StopBeforeMatch);
-    } else {
-      Exprs.push_back(Expr.get());
-    }
+        // We expect '}' rather than ')' at the end of an expansion-init-list.
+        SkipUntil(tok::comma,
+                  ParsingExpansionStmtInitList ? tok::r_brace : tok::r_paren,
+                  StopAtSemi | StopBeforeMatch);
+      } else {
+        Exprs.push_back(Expr.get());
+      }
 
-    if (Tok.isNot(tok::comma))
-      break;
-    // Move to the next argument, remember where the comma was.
-    Token Comma = Tok;
-    ConsumeToken();
+      if (Tok.isNot(tok::comma))
+        break;
+      // Move to the next argument, remember where the comma was.
+      Token Comma = Tok;
+      ConsumeToken();
 
-    // CWG 3061: Trailing commas are allowed in expansion-init-lists.
-    if (ParsingExpansionStmtInitList && Tok.is(tok::r_brace))
-      break;
+      // CWG 3061: Trailing commas are allowed in expansion-init-lists.
+      if (ParsingExpansionStmtInitList && Tok.is(tok::r_brace))
+        break;
 
-    checkPotentialAngleBracketDelimiter(Comma);
-  }
+      checkPotentialAngleBracketDelimiter(Comma);
+    }
+  });
   return SawError;
 }
 
@@ -3399,7 +3402,10 @@ ExprResult Parser::ParseBlockLiteralExpression() {
   }
   EnterExpressionEvaluationContextForFunction PotentiallyEvaluated(
        Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
-  StmtResult Stmt(ParseCompoundStatementBody());
+  StmtResult Stmt;
+  Actions.runWithSufficientStackSpace(
+      Tok.getLocation(), [&] { Stmt = ParseCompoundStatementBody(); });
+
   BlockScope.Exit();
   if (!Stmt.isInvalid())
     Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope());



More information about the cfe-commits mailing list