https://github.com/mygitljf updated https://github.com/llvm/llvm-project/pull/199098
>From 08edf9e90a4d4e6c812a8b52c43ee58dc8c4591a Mon Sep 17 00:00:00 2001 From: mygitljf <[email protected]> Date: Thu, 21 May 2026 19:31:48 +0000 Subject: [PATCH 1/3] [clang-format] Fix a crash on unbalanced `?` inside nested braces When `parseConditional` searches for the `:` of a ternary expression, it would unconditionally feed every token to `consumeToken`. On malformed input where a `}` reaches the ternary parser before any `:`, `consumeToken`'s `tok::r_brace` branch pops a `Scopes` frame owned by an enclosing `parseBrace`, leaving `Scopes` inconsistent with the actual brace nesting and tripping `assert(!Scopes.empty())` at the top of `parseBrace`'s loop on the next iteration. Bail out of `parseConditional` on an unbalanced `}` so the closing brace propagates up to the enclosing `parseBrace`, which pops the matching frame through its normal path. This mirrors the existing defensive check in `parseAngle` (TokenAnnotator.cpp:247). Fixes #199017 --- clang/lib/Format/TokenAnnotator.cpp | 5 +++++ clang/unittests/Format/FormatTest.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 43e4f6796b6dd..c3a65fd9eedb5 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1297,6 +1297,11 @@ class AnnotatingParser { next(); return true; } + // Avoid consuming an unbalanced `}` here: it would pop a Scopes frame + // owned by an enclosing parseBrace and trip its `!Scopes.empty()` + // assertion. See Issue #199017. + if (CurrentToken->is(tok::r_brace)) + return false; if (!consumeToken()) return false; } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 83e2c5b38ceaf..41b5605ef1b9e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14383,6 +14383,8 @@ TEST_F(FormatTest, IncorrectCodeUnbalancedBraces) { "};"); verifyNoCrash("decltype( {\n" " {"); + // Issue #199017 + verifyNoCrash("{{ < ? } a} b"); } TEST_F(FormatTest, IncorrectUnbalancedBracesInMacrosWithUnicode) { >From 5004f7091171238c9cb35c1c4920f49574e29942 Mon Sep 17 00:00:00 2001 From: mygitljf <[email protected]> Date: Sat, 23 May 2026 12:03:54 +0000 Subject: [PATCH 2/3] modify comments and move the position of verifyNoCrash --- clang/lib/Format/TokenAnnotator.cpp | 6 +++--- clang/unittests/Format/FormatTest.cpp | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index c3a65fd9eedb5..00b3fc0ad7eaa 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1297,9 +1297,9 @@ class AnnotatingParser { next(); return true; } - // Avoid consuming an unbalanced `}` here: it would pop a Scopes frame - // owned by an enclosing parseBrace and trip its `!Scopes.empty()` - // assertion. See Issue #199017. + // A `}` here would be consumed by consumeToken's r_brace branch + // and pop a Scopes frame owned by the enclosing parseBrace, leaving + // the Scopes stack out of sync with the actual brace nesting. if (CurrentToken->is(tok::r_brace)) return false; if (!consumeToken()) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 41b5605ef1b9e..11d649af53359 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14383,8 +14383,6 @@ TEST_F(FormatTest, IncorrectCodeUnbalancedBraces) { "};"); verifyNoCrash("decltype( {\n" " {"); - // Issue #199017 - verifyNoCrash("{{ < ? } a} b"); } TEST_F(FormatTest, IncorrectUnbalancedBracesInMacrosWithUnicode) { @@ -22510,6 +22508,7 @@ TEST_F(FormatTest, DoNotCrashOnInvalidInput) { verifyNoCrash(" tst %o5 ! are we doing the gray case?\n" "LY52: ! [internal]"); verifyNoCrash("operator foo *;"); + verifyNoCrash("{{ < ? } a} b"); } TEST_F(FormatTest, FormatsTableGenCode) { >From 901adecc2425e63c4293de9a0c42aa1370f856cb Mon Sep 17 00:00:00 2001 From: mygitljf <[email protected]> Date: Sat, 23 May 2026 13:13:35 +0000 Subject: [PATCH 3/3] move fix to parseBrace and add kw_operator regression test --- clang/lib/Format/TokenAnnotator.cpp | 11 ++++------- clang/unittests/Format/FormatTest.cpp | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 00b3fc0ad7eaa..a664e7713d0a0 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1214,9 +1214,11 @@ class AnnotatingParser { unsigned CommaCount = 0; while (CurrentToken) { - assert(!Scopes.empty()); + if (Scopes.empty()) + return false; if (CurrentToken->is(tok::r_brace)) { - assert(Scopes.back() == getScopeType(OpeningBrace)); + if (Scopes.back() != getScopeType(OpeningBrace)) + return false; Scopes.pop_back(); assert(OpeningBrace.Optional == CurrentToken->Optional); OpeningBrace.MatchingParen = CurrentToken; @@ -1297,11 +1299,6 @@ class AnnotatingParser { next(); return true; } - // A `}` here would be consumed by consumeToken's r_brace branch - // and pop a Scopes frame owned by the enclosing parseBrace, leaving - // the Scopes stack out of sync with the actual brace nesting. - if (CurrentToken->is(tok::r_brace)) - return false; if (!consumeToken()) return false; } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 11d649af53359..24508a593ad69 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14383,6 +14383,7 @@ TEST_F(FormatTest, IncorrectCodeUnbalancedBraces) { "};"); verifyNoCrash("decltype( {\n" " {"); + verifyNoCrash("{ operator } a } b"); } TEST_F(FormatTest, IncorrectUnbalancedBracesInMacrosWithUnicode) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
