[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