Andrea Pinski <[email protected]> writes:

> On Mon, Aug 31, 2026 at 7:42 AM Léo Hardt <[email protected]> wrote:

>>
>> 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.
>
> Ok.
>
>>
>> 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;
>> +    }

Unless I'm missing something...

This commit added an early return to builtin_has_include_1 that skips
the set to paren:

  if (!pfile->state.in_directive)
    {
      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;
  pfile->state.directive_wants_padding = true;
  const cpp_token *token = _cpp_get_token_no_padding (pfile);
  *paren = token->type == CPP_OPEN_PAREN;

But every call to builtin_has_include_1 has paren uninitialized:

static int
builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next)
{
  int result = 0;
  bool paren, bracket;
  char *fname = builtin_has_include_1 (pfile, (const char *) NODE_NAME (op),
                                       &paren, &bracket, NULL);

This is causing spurious test failures for me, seemingly from the
uninitialized read.

Aldy

Reply via email to