aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLewis Hyatt <lhyatt@gmail.com>2023-09-15 13:31:51 -0400
committerLewis Hyatt <lhyatt@gmail.com>2023-09-20 16:44:24 -0400
commit601dbf2a799f691688dfe78250b5bea2717b5b5e (patch)
treeb5309aa08914667b85299fe105b7c5881910a495
parentb512d705797a65dbfe3a9ad100218192c7528b02 (diff)
downloadgcc-601dbf2a799f691688dfe78250b5bea2717b5b5e.zip
gcc-601dbf2a799f691688dfe78250b5bea2717b5b5e.tar.gz
gcc-601dbf2a799f691688dfe78250b5bea2717b5b5e.tar.bz2
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.
-rw-r--r--gcc/testsuite/c-c++-common/cpp/pr61474-2.h1
-rw-r--r--gcc/testsuite/c-c++-common/cpp/pr61474.c5
-rw-r--r--gcc/testsuite/c-c++-common/cpp/pr61474.h6
-rw-r--r--libcpp/files.cc11
4 files changed, 21 insertions, 2 deletions
diff --git a/gcc/testsuite/c-c++-common/cpp/pr61474-2.h b/gcc/testsuite/c-c++-common/cpp/pr61474-2.h
new file mode 100644
index 0000000..6f70f09
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr61474-2.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/gcc/testsuite/c-c++-common/cpp/pr61474.c b/gcc/testsuite/c-c++-common/cpp/pr61474.c
new file mode 100644
index 0000000..f835a40
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr61474.c
@@ -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"
diff --git a/gcc/testsuite/c-c++-common/cpp/pr61474.h b/gcc/testsuite/c-c++-common/cpp/pr61474.h
new file mode 100644
index 0000000..d9e8c3a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/cpp/pr61474.h
@@ -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
diff --git a/libcpp/files.cc b/libcpp/files.cc
index 43a8894..27301d7 100644
--- a/libcpp/files.cc
+++ b/libcpp/files.cc
@@ -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