aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Basic/SourceManager.cpp20
-rw-r--r--test/PCH/inconsistent-pch.c15
2 files changed, 33 insertions, 2 deletions
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index a3e72e8b40..354bf7befb 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -56,9 +56,25 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const {
// Lazily create the Buffer for ContentCaches that wrap files.
if (!Buffer && Entry) {
- // FIXME: Should we support a way to not have to do this check over
- // and over if we cannot open the file?
Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize());
+
+ // If we were unable to open the file, then we are in an inconsistent
+ // situation where the content cache referenced a file which no longer
+ // exists. Most likely, we were using a stat cache with an invalid entry but
+ // the file could also have been removed during processing. Since we can't
+ // really deal with this situation, just create an empty buffer.
+ //
+ // FIXME: This is definitely not ideal, but our immediate clients can't
+ // currently handle returning a null entry here. Ideally we should detect
+ // that we are in an inconsistent situation and error out as quickly as
+ // possible.
+ if (!Buffer) {
+ const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
+ Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>");
+ char *Ptr = const_cast<char*>(Buffer->getBufferStart());
+ for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
+ Ptr[i] = FillStr[i % FillStr.size()];
+ }
}
return Buffer;
}
diff --git a/test/PCH/inconsistent-pch.c b/test/PCH/inconsistent-pch.c
new file mode 100644
index 0000000000..9573118c53
--- /dev/null
+++ b/test/PCH/inconsistent-pch.c
@@ -0,0 +1,15 @@
+// Check that we don't crash in an inconsistent situation created by the stat
+// cache.
+
+// RUN: echo 'void f0(float *a0);' > %t.h
+// RUN: clang-cc -emit-pch -o %t.h.pch %t.h
+// RUN: rm %t.h
+// RUN: not clang-cc -include-pch %t.h.pch %s 2> %t.err
+// RUN: FileCheck %s < %t.err
+
+// CHECK: inconsistent-pch.c:{{.*}}:{{.*}}: error: conflicting types for 'f0'
+// CHECK: void f0(int *a0);
+// CHECK: inconsistent-pch.c.tmp.h:{{.*}}:{{.*}}: note: previous declaration is here
+// CHECK: 2 diagnostics generated.
+
+void f0(int *a0);