Skip to content

Commit 8f0c865

Browse files
authored
Fix a crash with empty escape sequences when lexing (#102339)
The utilities we use for lexing string and character literals can be run in a mode where we pass a null pointer for the diagnostics engine. This mode is used by the format string checkers, for example. However, there were two places that failed to account for a null diagnostic engine pointer: `\o{}` and `\x{}`. This patch adds a check for a null pointer and correctly handles fallback behavior. Fixes #102218
1 parent bde2432 commit 8f0c865

File tree

3 files changed

+23
-6
lines changed

3 files changed

+23
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ Bug Fixes in This Version
175175
be used in C++.
176176
- Fixed a failed assertion when checking required literal types in C context. (#GH101304).
177177
- Fixed a crash when trying to transform a dependent address space type. Fixes #GH101685.
178+
- Fixed a crash when diagnosing format strings and encountering an empty
179+
delimited escape sequence (e.g., ``"\o{}"``). #GH102218
178180

179181
Bug Fixes to Compiler Builtins
180182
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Lex/LiteralSupport.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
190190
Delimited = true;
191191
ThisTokBuf++;
192192
if (*ThisTokBuf == '}') {
193-
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
194-
diag::err_delimited_escape_empty);
195-
return ResultChar;
193+
HadError = true;
194+
if (Diags)
195+
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
196+
diag::err_delimited_escape_empty);
196197
}
197198
} else if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) {
198199
if (Diags)
@@ -283,9 +284,10 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
283284
Delimited = true;
284285
++ThisTokBuf;
285286
if (*ThisTokBuf == '}') {
286-
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
287-
diag::err_delimited_escape_empty);
288-
return ResultChar;
287+
HadError = true;
288+
if (Diags)
289+
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
290+
diag::err_delimited_escape_empty);
289291
}
290292

291293
while (ThisTokBuf != ThisTokEnd) {

clang/test/Lexer/char-escapes-delimited.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,16 @@ void separators(void) {
123123
static_assert('\N??<DOLLAR SIGN??>' == '$'); // expected-warning 2{{trigraph converted}} \
124124
// ext-warning {{extension}} cxx23-warning {{C++23}}
125125
#endif
126+
127+
void GH102218(void) {
128+
// The format specifier checking code runs the lexer with diagnostics
129+
// disabled. This used to crash Clang for malformed \o and \x because the
130+
// lexer missed a null pointer check for the diagnostics engine in that case.
131+
extern int printf(const char *, ...);
132+
printf("\o{}"); // expected-error {{delimited escape sequence cannot be empty}}
133+
printf("\x{}"); // expected-error {{delimited escape sequence cannot be empty}}
134+
135+
// These cases always worked but are here for completeness.
136+
printf("\u{}"); // expected-error {{delimited escape sequence cannot be empty}}
137+
printf("\N{}"); // expected-error {{delimited escape sequence cannot be empty}}
138+
}

0 commit comments

Comments
 (0)