[clang] [clang-format] Fix '!Scopes.empty()' assertion in parseBrace (PR #199098)
via cfe-commits
cfe-commits at lists.llvm.org
Sat May 23 05:08:42 PDT 2026
https://github.com/mygitljf updated https://github.com/llvm/llvm-project/pull/199098
>From 08edf9e90a4d4e6c812a8b52c43ee58dc8c4591a Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Thu, 21 May 2026 19:31:48 +0000
Subject: [PATCH 1/2] [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 <2410316423 at qq.com>
Date: Sat, 23 May 2026 12:03:54 +0000
Subject: [PATCH 2/2] 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) {
More information about the cfe-commits
mailing list