[clang] [clang-format] Avoid crash on semicolons and unmatched braces (PR #234527)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 22 02:28:48 PDT 2026
https://github.com/r4nt updated https://github.com/llvm/llvm-project/pull/234527
>From 348466213df29c0862cc7001984854ee3447ba10 Mon Sep 17 00:00:00 2001
From: Manuel Klimek <klimek at google.com>
Date: Wed, 21 Oct 2026 21:47:55 +0200
Subject: [PATCH] [clang-format] Avoid crash on semicolons and unmatched braces
in TextProto
In UnwrappedLineParser::parseFile(), TextProto and Json inputs are parsed by
calling parseBracedList() directly instead of parseLevel(). Previously,
parseBracedList() returned early before eof() in two cases:
1. Encountering a semicolon (even though TextFormat protobufs allow ';' as an
optional field separator), which returned false without consuming the token
and unwound all enclosing parseBracedList() calls.
2. Encountering an unmatched closing '}' (e.g. in partial R"pb(...)pb" raw
string fragments concatenated via StrCat), which returned after consuming
'}' and left any remaining tokens unconsumed.
Both cases triggered the assert(eof()) in UnwrappedLineParser::parse().
---
clang/lib/Format/UnwrappedLineParser.cpp | 8 +++++---
.../unittests/Format/FormatTestTextProto.cpp | 19 +++++++++++++++++++
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 1b00e9015ea6e0..e5603feb379772 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -277,7 +277,8 @@ void UnwrappedLineParser::parseFile() {
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
if (Style.isTextProto() || (Style.isJson() && FormatTok->IsFirst))
- parseBracedList();
+ while (!eof())
+ parseBracedList();
else
parseLevel();
// Make sure to format the remaining tokens.
@@ -2670,10 +2671,11 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) {
break;
case tok::semi:
// JavaScript (or more precisely TypeScript) can have semicolons in braced
- // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
+ // lists (in so-called TypeMemberLists). TextProto and Proto options also
+ // allow semicolons as field separators. Thus, the semicolon cannot be
// used for error recovery if we have otherwise determined that this is
// a braced list.
- if (Style.isJavaScript()) {
+ if (Style.isJavaScript() || Style.isProto() || Style.isJson()) {
nextToken();
break;
}
diff --git a/clang/unittests/Format/FormatTestTextProto.cpp b/clang/unittests/Format/FormatTestTextProto.cpp
index 6cddb838a0abe3..f919af5b78dd8f 100644
--- a/clang/unittests/Format/FormatTestTextProto.cpp
+++ b/clang/unittests/Format/FormatTestTextProto.cpp
@@ -721,6 +721,25 @@ TEST_F(FormatTestTextProto, KeepsAmpersandsNextToKeys) {
"}");
}
+TEST_F(FormatTestTextProto, SupportsSemicolonSeparators) {
+ verifyFormat("field_a: OK; field_b: OK");
+ verifyFormat("field_a: OK;\n"
+ "field_b { field_c: OK };\n"
+ "field_d: OKOKOK;\n"
+ "field_e: OK");
+ verifyFormat("msg_field <\n"
+ " field_a: OK;\n"
+ " field_b: <>;\n"
+ " field_c: OK\n"
+ ">");
+}
+
+TEST_F(FormatTestTextProto, DoesNotCrashOnUnmatchedClosingBrace) {
+ verifyNoCrash("field_a: 1 } field_b: 2");
+ verifyNoCrash("} field_a: 1");
+ verifyNoCrash("msg { field_a: 1 } } field_b: 2");
+}
+
} // namespace
} // namespace test
} // namespace format
More information about the cfe-commits
mailing list