fix(libcpp): Don't ICE parsing __has_include outside directive.
cc: libcpp maintainers.

Fixes an ICE wherein 'glue_header_name' is called outside
parsing a preprocessor directive, causing an entire file to
be read and presumed to be a header name. Then, on the next
read (the closing '>' or ')'), the parser ICEs since the input
has already come to an end.

Affects __has_include and __has_embed when used outside directives.
Minimal reproducible crash has two tokens (both gcc and g++):

  __has_include<

Given glue_header_name was written for usage inside preprocessor
parsing, we could either change it or not call it in case of errors.
I opted to bail out early on an error case, since there is no chance
it could influence valid code parsing.

See more on https://gcc.gnu.org/PR121508.

  PR preprocessor/121508
  PR preprocessor/123339

libcpp/ChangeLog:

        * macro.cc (builtin_has_include_1): Bail early if
        not on a preprocessor directive.

Signed-off-by: Léo Hardt <[email protected]>
---
 libcpp/macro.cc | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libcpp/macro.cc b/libcpp/macro.cc
index 736c360336d..064df1d4134 100644
--- a/libcpp/macro.cc
+++ b/libcpp/macro.cc
@@ -392,8 +392,11 @@ builtin_has_include_1 (cpp_reader *pfile, const char *name, bool *paren,
                       bool *bracket, location_t *loc)
 {
   if (!pfile->state.in_directive)
-    cpp_error (pfile, CPP_DL_ERROR,
-              "%qs used outside of preprocessing directive", name);
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+                "%qs used outside of preprocessing directive", name);
+      return NULL;
+    }

   pfile->state.angled_headers = true;
   const auto sav_padding = pfile->state.directive_wants_padding;
--
2.47.3


Reply via email to