[clang] 71ad307 - [Clang] prevent crash on unterminated __has_embed (#163107)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 15 09:00:30 PDT 2025
Author: Oleksandr T.
Date: 2025-10-15T19:00:26+03:00
New Revision: 71ad307d231c8048327c7a74c1bb38f0b86fde15
URL: https://github.com/llvm/llvm-project/commit/71ad307d231c8048327c7a74c1bb38f0b86fde15
DIFF: https://github.com/llvm/llvm-project/commit/71ad307d231c8048327c7a74c1bb38f0b86fde15.diff
LOG: [Clang] prevent crash on unterminated __has_embed (#163107)
Fixes #162953
---
This PR addresses the issue of Clang crashing on unterminated
`__has_embed` by guarding all `DiscardUntilEndOfDirective` paths with
the contextual end token and diagnosing the missing `)` before reporting
_unknown_ parameters.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Lex/PPDirectives.cpp
clang/lib/Lex/PPMacroExpansion.cpp
clang/test/Preprocessor/embed___has_embed_parsing_errors.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 053d8d631cf4a..afe3d4674b610 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -413,6 +413,7 @@ Bug Fixes in This Version
(#GH159080)
- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898)
- Fixed a failed assertion with empty filename in ``#embed`` directive. (#GH162951)
+- Fixed a crash triggered by unterminated ``__has_embed``. (#GH162953)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index b40085227df00..6a5e5d4bad3a6 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -3665,14 +3665,14 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
std::pair<tok::TokenKind, SourceLocation> Matches) {
Diag(CurTok, diag::err_expected) << Expected;
Diag(Matches.second, diag::note_matching) << Matches.first;
- if (CurTok.isNot(tok::eod))
+ if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
};
auto ExpectOrDiagAndSkipToEOD = [&](tok::TokenKind Kind) {
if (CurTok.isNot(Kind)) {
Diag(CurTok, diag::err_expected) << Kind;
- if (CurTok.isNot(tok::eod))
+ if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return false;
}
@@ -3763,7 +3763,7 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
if (Result.isNegative()) {
Diag(CurTok, diag::err_requires_positive_value)
<< toString(Result, 10) << /*positive*/ 0;
- if (CurTok.isNot(tok::eod))
+ if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return std::nullopt;
}
@@ -3906,7 +3906,7 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
}
if (!ForHasEmbed) {
Diag(ParamStartLoc, diag::err_pp_unknown_parameter) << 1 << Parameter;
- if (CurTok.isNot(tok::eod))
+ if (CurTok.isNot(EndTokenKind))
DiscardUntilEndOfDirective(CurTok);
return std::nullopt;
}
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index dec1956ea0f9a..dd80ae586a1f6 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1262,16 +1262,11 @@ EmbedResult Preprocessor::EvaluateHasEmbed(Token &Tok, IdentifierInfo *II) {
std::optional<LexEmbedParametersResult> Params =
this->LexEmbedParameters(Tok, /*ForHasEmbed=*/true);
- assert((Params || Tok.is(tok::eod)) &&
- "expected success or to be at the end of the directive");
if (!Params)
return EmbedResult::Invalid;
- if (Params->UnrecognizedParams > 0)
- return EmbedResult::NotFound;
-
- if (!Tok.is(tok::r_paren)) {
+ if (Tok.isNot(tok::r_paren)) {
Diag(this->getLocForEndOfToken(FilenameLoc), diag::err_pp_expected_after)
<< II << tok::r_paren;
Diag(LParenLoc, diag::note_matching) << tok::l_paren;
@@ -1280,6 +1275,9 @@ EmbedResult Preprocessor::EvaluateHasEmbed(Token &Tok, IdentifierInfo *II) {
return EmbedResult::Invalid;
}
+ if (Params->UnrecognizedParams > 0)
+ return EmbedResult::NotFound;
+
SmallString<128> FilenameBuffer;
StringRef Filename = this->getSpelling(FilenameTok, FilenameBuffer);
if (Filename.empty())
diff --git a/clang/test/Preprocessor/embed___has_embed_parsing_errors.c b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
index 9c512a4882e2d..8ab53f6b89c0d 100644
--- a/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
+++ b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
@@ -250,3 +250,35 @@
#if __has_embed("") // expected-error {{empty filename}}
#endif
+
+// expected-error at +3 {{missing ')' after '__has_embed'}} \
+ expected-error at +3 {{expected value in expression}} \
+ expected-note at +3 {{to match this '('}}
+#if __has_embed (__FILE__ foo limit(1)
+#endif
+
+//--- test3.c
+// expected-error at +3 {{missing ')' after '__has_embed'}} \
+ expected-error at +3 {{expected value in expression}} \
+ expected-note at +3 {{to match this '('}}
+#if __has_embed (__FILE__ foo
+#endif
+
+// expected-error at +3 {{missing ')' after '__has_embed'}} \
+ expected-error at +3 {{expected value in expression}} \
+ expected-note at +3 {{to match this '('}}
+#if __has_embed ("a" foo()
+#endif
+
+// expected-error at +3 {{missing ')' after '__has_embed'}} \
+ expected-error at +3 {{expected value in expression}} \
+ expected-note at +3 {{to match this '('}}
+#if __has_embed ("a" bar() foo
+#endif
+
+// expected-error at +3 {{missing ')' after '__has_embed'}} \
+ expected-error at +3 {{expected value in expression}} \
+ expected-note at +3 {{to match this '('}}
+#if __has_embed (__FILE__ limit(1) foo
+int a = __has_embed (__FILE__);
+#endif
More information about the cfe-commits
mailing list