ソースを参照

[PCH] Recover gracefully if the ASTReader detects that a file is different
from the one stored in the PCH/AST, while trying to load a SLocEntry.

We verify that all files of the PCH did not change before loading it but this is not enough because:

- The AST may have been 1) kept around, 2) to do queries on it.
- We may have 1) verified the PCH and 2) started parsing.

Between 1) and 2) files may change and we are going to have crashes because the rest of clang
cannot deal with the ASTReader failing to read a SLocEntry.

Handle this by recovering gracefully in such a case, by initializing the SLocEntry
with the info from the PCH/AST as well as reporting failure by the ASTReader.

rdar://10888929

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151004 91177308-0d34-0410-b5e6-96231b3b80d8

Argyrios Kyrtzidis 13 年 前
コミット
a4c29b6e55

+ 12 - 6
include/clang/Basic/SourceManager.h

@@ -519,7 +519,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
   ///
   ///
   /// Negative FileIDs are indexes into this table. To get from ID to an index,
   /// Negative FileIDs are indexes into this table. To get from ID to an index,
   /// use (-ID - 2).
   /// use (-ID - 2).
-  std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
+  mutable std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
 
 
   /// \brief The starting offset of the next local SLocEntry.
   /// \brief The starting offset of the next local SLocEntry.
   ///
   ///
@@ -576,6 +576,8 @@ class SourceManager : public RefCountedBase<SourceManager> {
   // Cache for the "fake" buffer used for error-recovery purposes.
   // Cache for the "fake" buffer used for error-recovery purposes.
   mutable llvm::MemoryBuffer *FakeBufferForRecovery;
   mutable llvm::MemoryBuffer *FakeBufferForRecovery;
 
 
+  mutable SrcMgr::ContentCache *FakeContentCacheForRecovery;
+
   /// \brief Lazily computed map of macro argument chunks to their expanded
   /// \brief Lazily computed map of macro argument chunks to their expanded
   /// source location.
   /// source location.
   typedef std::map<unsigned, SourceLocation> MacroArgsMap;
   typedef std::map<unsigned, SourceLocation> MacroArgsMap;
@@ -1260,9 +1262,9 @@ public:
   const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index,
   const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index,
                                               bool *Invalid = 0) const {
                                               bool *Invalid = 0) const {
     assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
     assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
-    if (!SLocEntryLoaded[Index])
-      ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2));
-    return LoadedSLocEntryTable[Index];
+    if (SLocEntryLoaded[Index])
+      return LoadedSLocEntryTable[Index];
+    return loadSLocEntry(Index, Invalid);
   }
   }
 
 
   const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
   const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
@@ -1313,6 +1315,9 @@ public:
 
 
 private:
 private:
   const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
   const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
+  const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const;
+
+  const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const;
 
 
   /// \brief Get the entry with the given unwrapped FileID.
   /// \brief Get the entry with the given unwrapped FileID.
   const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
   const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
@@ -1322,8 +1327,9 @@ private:
     return getLocalSLocEntry(static_cast<unsigned>(ID));
     return getLocalSLocEntry(static_cast<unsigned>(ID));
   }
   }
 
 
-  const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID) const {
-    return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2));
+  const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID,
+                                                  bool *Invalid = 0) const {
+    return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid);
   }
   }
 
 
   /// createExpansionLoc - Implements the common elements of storing an
   /// createExpansionLoc - Implements the common elements of storing an

+ 34 - 1
lib/Basic/SourceManager.cpp

@@ -370,7 +370,8 @@ LineTableInfo &SourceManager::getLineTable() {
 SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr)
 SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr)
   : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
   : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
     ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
     ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
-    NumBinaryProbes(0), FakeBufferForRecovery(0) {
+    NumBinaryProbes(0), FakeBufferForRecovery(0),
+    FakeContentCacheForRecovery(0) {
   clearIDTables();
   clearIDTables();
   Diag.setSourceManager(this);
   Diag.setSourceManager(this);
 }
 }
@@ -396,6 +397,7 @@ SourceManager::~SourceManager() {
   }
   }
   
   
   delete FakeBufferForRecovery;
   delete FakeBufferForRecovery;
+  delete FakeContentCacheForRecovery;
 
 
   for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
   for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
          I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
          I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
@@ -469,6 +471,25 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
   return Entry;
   return Entry;
 }
 }
 
 
+const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
+                                                      bool *Invalid) const {
+  assert(!SLocEntryLoaded[Index]);
+  if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) {
+    if (Invalid)
+      *Invalid = true;
+    // If the file of the SLocEntry changed we could still have loaded it.
+    if (!SLocEntryLoaded[Index]) {
+      // Try to recover; create a SLocEntry so the rest of clang can handle it.
+      LoadedSLocEntryTable[Index] = SLocEntry::get(0,
+                                 FileInfo::get(SourceLocation(),
+                                               getFakeContentCacheForRecovery(),
+                                               SrcMgr::C_User));
+    }
+  }
+
+  return LoadedSLocEntryTable[Index];
+}
+
 std::pair<int, unsigned>
 std::pair<int, unsigned>
 SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
 SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
                                          unsigned TotalSize) {
                                          unsigned TotalSize) {
@@ -491,6 +512,18 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
   return FakeBufferForRecovery;
   return FakeBufferForRecovery;
 }
 }
 
 
+/// \brief As part of recovering from missing or changed content, produce a
+/// fake content cache.
+const SrcMgr::ContentCache *
+SourceManager::getFakeContentCacheForRecovery() const {
+  if (!FakeContentCacheForRecovery) {
+    FakeContentCacheForRecovery = new ContentCache();
+    FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(),
+                                               /*DoNotFree=*/true);
+  }
+  return FakeContentCacheForRecovery;
+}
+
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // Methods to create new FileID's and macro expansions.
 // Methods to create new FileID's and macro expansions.
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//

+ 8 - 1
lib/Serialization/ASTReader.cpp

@@ -1111,6 +1111,10 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
       return Failure;
       return Failure;
     }
     }
 
 
+    // We will detect whether a file changed and return 'Failure' for it, but
+    // we will also try to fail gracefully by setting up the SLocEntry.
+    ASTReader::ASTReadResult Result = Success;
+
     bool OverriddenBuffer = Record[6];
     bool OverriddenBuffer = Record[6];
     
     
     std::string OrigFilename(BlobStart, BlobStart + BlobLen);
     std::string OrigFilename(BlobStart, BlobStart + BlobLen);
@@ -1149,7 +1153,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
 #endif
 #endif
         )) {
         )) {
       Error(diag::err_fe_pch_file_modified, Filename);
       Error(diag::err_fe_pch_file_modified, Filename);
-      return Failure;
+      Result = Failure;
     }
     }
 
 
     SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
     SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
@@ -1193,6 +1197,9 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
                                            Filename);
                                            Filename);
       SourceMgr.overrideFileContents(File, Buffer);
       SourceMgr.overrideFileContents(File, Buffer);
     }
     }
+
+    if (Result == Failure)
+      return Failure;
     break;
     break;
   }
   }