libcpp: Fix ICE on #include after a line marker directive [PR61474]

As noted in the PR, GCC will segfault if a file name is first seen in a
linemarker directive, and then later seen in a normal #include.  This is
because the fake include process adds the file to the cache with a null PATH
member. The normal #include finds this file in the cache and then attempts
to use the null PATH.  Resolve by adding the file to the cache with a unique
starting directory, so that the fake entry will only be found by a
subsequent fake include, not by a real one.

libcpp/ChangeLog:

	PR preprocessor/61474
	* files.cc (_cpp_find_file): Set DONT_READ to TRUE for fake
	include files.
	(_cpp_fake_include): Pass a unique cpp_dir* address so
	the fake file will not be found when looked up for real.

gcc/testsuite/ChangeLog:

	PR preprocessor/61474
	* c-c++-common/cpp/pr61474-2.h: New test.
	* c-c++-common/cpp/pr61474.c: New test.
	* c-c++-common/cpp/pr61474.h: New test.
This commit is contained in:
Lewis Hyatt 2023-09-15 13:31:51 -04:00
parent b512d70579
commit 601dbf2a79
4 changed files with 21 additions and 2 deletions

View File

@ -0,0 +1 @@
#pragma once

View File

@ -0,0 +1,5 @@
/* { dg-do preprocess } */
#include "pr61474.h"
/* Make sure that the file can be included for real, after it was
fake-included by the linemarker directives in pr61474.h. */
#include "pr61474-2.h"

View File

@ -0,0 +1,6 @@
/* Create a fake include for pr61474-2.h and exercise looking it up. */
/* Use #pragma once to check also that the fake-include entry in the file
cache does not cause a problem in libcpp/files.cc:has_unique_contents(). */
#pragma once
# 1 "pr61474-2.h" 1
# 2 "pr61474-2.h" 1

View File

@ -541,7 +541,9 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
= (kind == _cpp_FFK_PRE_INCLUDE
|| (pfile->buffer && pfile->buffer->file->implicit_preinclude));
if (kind != _cpp_FFK_FAKE)
if (kind == _cpp_FFK_FAKE)
file->dont_read = true;
else
/* Try each path in the include chain. */
for (;;)
{
@ -1490,7 +1492,12 @@ cpp_clear_file_cache (cpp_reader *pfile)
void
_cpp_fake_include (cpp_reader *pfile, const char *fname)
{
_cpp_find_file (pfile, fname, pfile->buffer->file->dir, 0, _cpp_FFK_FAKE, 0);
/* It does not matter what are the contents of fake_source_dir, it will never
be inspected; we just use its address to uniquely signify that this file
was added as a fake include, so a later call to _cpp_find_file (to include
the file for real) won't find the fake one in the hash table. */
static cpp_dir fake_source_dir;
_cpp_find_file (pfile, fname, &fake_source_dir, 0, _cpp_FFK_FAKE, 0);
}
/* Not everyone who wants to set system-header-ness on a buffer can