[clang] [clang-format] Fix a crash on triple-bracket input like `[[[a]]` (PR #199103)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 5 06:30:17 PDT 2026
https://github.com/mygitljf updated https://github.com/llvm/llvm-project/pull/199103
>From 70d1648e9d5a973acd5e710f485764be63d80038 Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Thu, 21 May 2026 19:53:27 +0000
Subject: [PATCH 1/3] [clang-format] Fix a crash on triple-bracket input like
`[[[a]]`
`isCppAttribute` only checks the tokens following `[[`, so for malformed
input `[[[a]]` it returns true on the *middle* `[`: that token's
`Next`/`Next->Next` look like a valid `[[ident...]]` sequence. The middle
`[` is then annotated as `TT_AttributeLSquare` while the outer `[` stays
as a raw `tok::l_square`, which violates the invariant guarded by
`assert(Left.isNot(tok::l_square))` in `canBreakBefore` and aborts the
process.
Reject the C++ attribute classification when the candidate `[[` is
itself preceded by another `[`. Legal C++ never has `[[[` in any
context, so this is a strict refinement that mirrors the existing
defensive check that excludes ObjC `@[...]` array literals.
Fixes #199010
---
clang/lib/Format/TokenAnnotator.cpp | 6 ++++++
clang/unittests/Format/FormatTest.cpp | 3 +++
2 files changed, 9 insertions(+)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 43e4f6796b6dd..63b4f65418a93 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -90,6 +90,12 @@ static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
// The first square bracket is part of an ObjC array literal
if (Tok.Previous && Tok.Previous->is(tok::at))
return false;
+ // A C++ attribute specifier '[[...]]' never appears directly inside another
+ // '['. Treating malformed input like '[[[a]]' as one would mis-annotate the
+ // inner '[' as TT_AttributeLSquare while leaving the outer '[' as a raw
+ // tok::l_square, tripping an assertion in canBreakBefore.
+ if (Tok.Previous && Tok.Previous->is(tok::l_square))
+ return false;
const FormatToken *AttrTok = Tok.Next->Next;
if (!AttrTok)
return false;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 83e2c5b38ceaf..6f01492ddce82 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -22508,6 +22508,9 @@ TEST_F(FormatTest, DoNotCrashOnInvalidInput) {
verifyNoCrash(" tst %o5 ! are we doing the gray case?\n"
"LY52: ! [internal]");
verifyNoCrash("operator foo *;");
+ verifyNoCrash("[[[a]]");
+ verifyNoCrash("[[[a]]]");
+ verifyNoCrash("[[ [a] ]]");
}
TEST_F(FormatTest, FormatsTableGenCode) {
>From 56ccc88183af0f3dfac5dc1ed92df5ea9022d7da Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Sat, 23 May 2026 10:05:12 +0000
Subject: [PATCH 2/3] [clang-format] simplify annotations
---
clang/lib/Format/TokenAnnotator.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 63b4f65418a93..b628c309028ab 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -90,10 +90,7 @@ static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
// The first square bracket is part of an ObjC array literal
if (Tok.Previous && Tok.Previous->is(tok::at))
return false;
- // A C++ attribute specifier '[[...]]' never appears directly inside another
- // '['. Treating malformed input like '[[[a]]' as one would mis-annotate the
- // inner '[' as TT_AttributeLSquare while leaving the outer '[' as a raw
- // tok::l_square, tripping an assertion in canBreakBefore.
+ // Avoid mis-annotating the inner '[[' of malformed input.
if (Tok.Previous && Tok.Previous->is(tok::l_square))
return false;
const FormatToken *AttrTok = Tok.Next->Next;
>From 6bf92d05e5a976efed20e0567d48e8257d341c9f Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Fri, 5 Jun 2026 20:37:52 +0800
Subject: [PATCH 3/3] [clang-format] simplify attribute check
---
clang/lib/Format/TokenAnnotator.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index b628c309028ab..d04677716e061 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -87,11 +87,7 @@ static bool isKeywordWithCondition(const FormatToken &Tok) {
static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square))
return false;
- // The first square bracket is part of an ObjC array literal
- if (Tok.Previous && Tok.Previous->is(tok::at))
- return false;
- // Avoid mis-annotating the inner '[[' of malformed input.
- if (Tok.Previous && Tok.Previous->is(tok::l_square))
+ if (Tok.Previous && Tok.Previous->isOneOf(tok::at, tok::l_square))
return false;
const FormatToken *AttrTok = Tok.Next->Next;
if (!AttrTok)
More information about the cfe-commits
mailing list