[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