llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: rishit53 <details> <summary>Changes</summary> ## Summary Fixes a stack overflow crash when parsing deeply nested expression lists and block literals (e.g. deeply nested function calls and blocks). ## Root Cause `ParseExpressionList` and `ParseBlockLiteralExpression` (which invokes `ParseCompoundStatementBody` directly) recurse without stack exhaustion guards under deep nesting. ## Solution Wrapped parsing bodies with `Actions.runWithSufficientStackSpace(...)` in both functions within `clang/lib/Parse/ParseExpr.cpp`, following existing patterns used for compound statements and unary operator chains. Fixes #<!-- -->121952 --- Full diff: https://github.com/llvm/llvm-project/pull/235488.diff 2 Files Affected: - (modified) clang/docs/ReleaseNotes.md (+1) - (modified) clang/lib/Parse/ParseExpr.cpp (+49-43) ``````````diff 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()); `````````` </details> https://github.com/llvm/llvm-project/pull/235488 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
