[cfe-commits] r129839 - in /cfe/trunk: include/clang/Basic/SourceManager.h include/clang/Serialization/ASTReader.h lib/Basic/SourceManager.cpp lib/Serialization/ASTReader.cpp tools/libclang/CIndex.cpp tools/libclang/CIndexInclusionStack.cpp

Douglas Gregor dgregor at apple.com
Tue Apr 19 17:21:03 PDT 2011


Author: dgregor
Date: Tue Apr 19 19:21:03 2011
New Revision: 129839

URL: http://llvm.org/viewvc/llvm-project?rev=129839&view=rev
Log:
Teach SourceManager::getSLocEntry() that it can fail due to problems
during deserialization from  a precompiled header, and update all of
its callers to note when this problem occurs and recover (more)
gracefully. Fixes <rdar://problem/9119249>.

Modified:
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Basic/SourceManager.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CIndexInclusionStack.cpp

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Tue Apr 19 19:21:03 2011
@@ -314,7 +314,10 @@
   virtual ~ExternalSLocEntrySource();
 
   /// \brief Read the source location entry with index ID.
-  virtual void ReadSLocEntry(unsigned ID) = 0;
+  ///
+  /// \returns true if an error occurred that prevented the source-location
+  /// entry from being loaded.
+  virtual bool ReadSLocEntry(unsigned ID) = 0;
 };
   
 
@@ -377,7 +380,7 @@
 /// Spelling locations represent where the bytes corresponding to a token came
 /// from and instantiation locations represent where the location is in the
 /// user's view.  In the case of a macro expansion, for example, the spelling
-/// location indicates where the expanded token came from and the instantiation
+/// location indicates  where the expanded token came from and the instantiation
 /// location specifies where it was expanded.
 class SourceManager : public llvm::RefCountedBase<SourceManager> {
   /// \brief Diagnostic object.
@@ -445,6 +448,9 @@
   // Cache results for the isBeforeInTranslationUnit method.
   mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
 
+  // Cache for the "fake" buffer used for error-recovery purposes.
+  mutable llvm::MemoryBuffer *FakeBufferForRecovery;
+  
   // SourceManager doesn't support copy construction.
   explicit SourceManager(const SourceManager&);
   void operator=(const SourceManager&);
@@ -571,18 +577,42 @@
   /// buffer and returns a non-empty error string.
   const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc,
                                       bool *Invalid = 0) const {
-    return getSLocEntry(FID).getFile().getContentCache()
-       ->getBuffer(Diag, *this, Loc, Invalid);
+    bool MyInvalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+    if (MyInvalid || !Entry.isFile()) {
+      if (Invalid)
+        *Invalid = true;
+      
+      return getFakeBufferForRecovery();
+    }
+        
+    return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc, 
+                                                        Invalid);
   }
 
   const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
-    return getSLocEntry(FID).getFile().getContentCache()
-       ->getBuffer(Diag, *this, SourceLocation(), Invalid);
+    bool MyInvalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+    if (MyInvalid || !Entry.isFile()) {
+      if (Invalid)
+        *Invalid = true;
+      
+      return getFakeBufferForRecovery();
+    }
+
+    return Entry.getFile().getContentCache()->getBuffer(Diag, *this, 
+                                                        SourceLocation(), 
+                                                        Invalid);
   }
   
   /// getFileEntryForID - Returns the FileEntry record for the provided FileID.
   const FileEntry *getFileEntryForID(FileID FID) const {
-    return getSLocEntry(FID).getFile().getContentCache()->OrigEntry;
+    bool MyInvalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+    if (MyInvalid || !Entry.isFile())
+      return 0;
+    
+    return Entry.getFile().getContentCache()->OrigEntry;
   }
 
   /// Returns the FileEntry record for the provided SLocEntry.
@@ -622,8 +652,12 @@
   /// first byte of the specified file.
   SourceLocation getLocForStartOfFile(FileID FID) const {
     assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
-    assert(getSLocEntry(FID).isFile() && "FileID is not a file");
-    unsigned FileOffset = getSLocEntry(FID).getOffset();
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return SourceLocation();
+    
+    unsigned FileOffset = Entry.getOffset();
     return SourceLocation::getFileLoc(FileOffset);
   }
 
@@ -851,17 +885,22 @@
   //  any other external source).
   unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
 
-  const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const {
+  const SrcMgr::SLocEntry &getSLocEntry(unsigned ID, bool *Invalid = 0) const {
     assert(ID < SLocEntryTable.size() && "Invalid id");
+    // If we haven't loaded this source-location entry from the external source
+    // yet, do so now.
     if (ExternalSLocEntries &&
         ID < SLocEntryLoaded.size() &&
-        !SLocEntryLoaded[ID])
-      ExternalSLocEntries->ReadSLocEntry(ID);
+        !SLocEntryLoaded[ID] &&
+        ExternalSLocEntries->ReadSLocEntry(ID) &&
+        Invalid)
+      *Invalid = true;
+
     return SLocEntryTable[ID];
   }
 
-  const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
-    return getSLocEntry(FID.ID);
+  const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
+    return getSLocEntry(FID.ID, Invalid);
   }
 
   unsigned getNextOffset() const { return NextOffset; }
@@ -877,6 +916,8 @@
   void ClearPreallocatedSLocEntries();
 
 private:
+  const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
+
   /// isOffsetInFileID - Return true if the specified FileID contains the
   /// specified SourceLocation offset.  This is a very hot method.
   inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const {

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Tue Apr 19 19:21:03 2011
@@ -1120,7 +1120,7 @@
   }
 
   /// \brief Read the source location entry with index ID.
-  virtual void ReadSLocEntry(unsigned ID);
+  virtual bool ReadSLocEntry(unsigned ID);
 
   Selector DecodeSelector(unsigned Idx);
 

Modified: cfe/trunk/lib/Basic/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/SourceManager.cpp?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/SourceManager.cpp (original)
+++ cfe/trunk/lib/Basic/SourceManager.cpp Tue Apr 19 19:21:03 2011
@@ -278,7 +278,12 @@
                                 int FilenameID) {
   std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
 
-  const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+  bool Invalid = false;
+  const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+  if (!Entry.isFile() || Invalid)
+    return;
+  
+  const SrcMgr::FileInfo &FileInfo = Entry.getFile();
 
   // Remember that this file has #line directives now if it doesn't already.
   const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -302,7 +307,13 @@
   }
 
   std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
-  const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+
+  bool Invalid = false;
+  const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+  if (!Entry.isFile() || Invalid)
+    return;
+  
+  const SrcMgr::FileInfo &FileInfo = Entry.getFile();
 
   // Remember that this file has #line directives now if it doesn't already.
   const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -341,7 +352,7 @@
 SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
   : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
     ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
-    NumBinaryProbes(0) {
+    NumBinaryProbes(0), FakeBufferForRecovery(0) {
   clearIDTables();
   Diag.setSourceManager(this);
 }
@@ -361,6 +372,8 @@
     I->second->~ContentCache();
     ContentCacheAlloc.Deallocate(I->second);
   }
+  
+  delete FakeBufferForRecovery;
 }
 
 void SourceManager::clearIDTables() {
@@ -455,6 +468,15 @@
   ExternalSLocEntries = 0;
 }
 
+/// \brief As part of recovering from missing or changed content, produce a
+/// fake, non-empty buffer.
+const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
+  if (!FakeBufferForRecovery)
+    FakeBufferForRecovery
+      = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
+  
+  return FakeBufferForRecovery;
+}
 
 //===----------------------------------------------------------------------===//
 // Methods to create new FileID's and instantiations.
@@ -554,8 +576,8 @@
 
 llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
   bool MyInvalid = false;
-  const SLocEntry &SLoc = getSLocEntry(FID.ID);
-  if (!SLoc.isFile()) {
+  const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid);
+  if (!SLoc.isFile() || MyInvalid) {
     if (Invalid) 
       *Invalid = true;
     return "<<<<<INVALID SOURCE LOCATION>>>>>";
@@ -583,7 +605,8 @@
 /// SLocEntryTable which contains the specified location.
 ///
 FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
-  assert(SLocOffset && "Invalid FileID");
+  if (!SLocOffset)
+    return FileID::get(0);
 
   // After the first and second level caches, I see two common sorts of
   // behavior: 1) a lot of searched FileID's are "near" the cached file location
@@ -611,8 +634,13 @@
   unsigned NumProbes = 0;
   while (1) {
     --I;
-    if (ExternalSLocEntries)
-      getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
+    if (ExternalSLocEntries) {
+      bool Invalid = false;
+      getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid);
+      if (Invalid)
+        return FileID::get(0);
+    }
+    
     if (I->getOffset() <= SLocOffset) {
 #if 0
       printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
@@ -642,9 +670,13 @@
   unsigned LessIndex = 0;
   NumProbes = 0;
   while (1) {
+    bool Invalid = false;
     unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
-    unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
-
+    unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid)
+                                                                  .getOffset();
+    if (Invalid)
+      return FileID::get(0);
+    
     ++NumProbes;
 
     // If the offset of the midpoint is too large, chop the high side of the
@@ -794,9 +826,16 @@
 
   // Note that calling 'getBuffer()' may lazily page in a source file.
   bool CharDataInvalid = false;
+  const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
+  if (CharDataInvalid || !Entry.isFile()) {
+    if (Invalid)
+      *Invalid = true;
+    
+    return "<<<<INVALID BUFFER>>>>";
+  }
   const llvm::MemoryBuffer *Buffer
-    = getSLocEntry(LocInfo.first).getFile().getContentCache()
-    ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
+    = Entry.getFile().getContentCache()
+                  ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
   if (Invalid)
     *Invalid = CharDataInvalid;
   return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -912,10 +951,18 @@
   ContentCache *Content;
   if (LastLineNoFileIDQuery == FID)
     Content = LastLineNoContentCache;
-  else
-    Content = const_cast<ContentCache*>(getSLocEntry(FID)
-                                        .getFile().getContentCache());
-
+  else {
+    bool MyInvalid = false;
+    const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+    if (MyInvalid || !Entry.isFile()) {
+      if (Invalid)
+        *Invalid = true;
+      return 1;
+    }
+    
+    Content = const_cast<ContentCache*>(Entry.getFile().getContentCache());
+  }
+  
   // If this is the first use of line information for this buffer, compute the
   /// SourceLineCache for it on demand.
   if (Content->SourceLineCache == 0) {
@@ -1042,7 +1089,12 @@
 SourceManager::getFileCharacteristic(SourceLocation Loc) const {
   assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
   std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
-  const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+  bool Invalid = false;
+  const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
+  if (Invalid || !SEntry.isFile())
+    return C_User;
+  
+  const SrcMgr::FileInfo &FI = SEntry.getFile();
 
   // If there are no #line directives in this file, just return the whole-file
   // state.
@@ -1085,7 +1137,12 @@
   // Presumed locations are always for instantiation points.
   std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
 
-  const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+  bool Invalid = false;
+  const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+  if (Invalid || !Entry.isFile())
+    return PresumedLoc();
+  
+  const SrcMgr::FileInfo &FI = Entry.getFile();
   const SrcMgr::ContentCache *C = FI.getContentCache();
 
   // To get the source name, first consult the FileEntry (if one exists)
@@ -1096,7 +1153,7 @@
     Filename = C->OrigEntry->getName();
   else
     Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
-  bool Invalid = false;
+
   unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
   if (Invalid)
     return PresumedLoc();
@@ -1173,7 +1230,11 @@
   llvm::Optional<ino_t> SourceFileInode;
   llvm::Optional<llvm::StringRef> SourceFileName;
   if (!MainFileID.isInvalid()) {
-    const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
+    bool Invalid = false;
+    const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
+    if (Invalid)
+      return SourceLocation();
+    
     if (MainSLoc.isFile()) {
       const ContentCache *MainContentCache
         = MainSLoc.getFile().getContentCache();
@@ -1206,7 +1267,11 @@
     // The location we're looking for isn't in the main file; look
     // through all of the source locations.
     for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
-      const SLocEntry &SLoc = getSLocEntry(I);
+      bool Invalid = false;
+      const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+      if (Invalid)
+        return SourceLocation();
+      
       if (SLoc.isFile() && 
           SLoc.getFile().getContentCache() &&
           SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
@@ -1224,8 +1289,12 @@
        (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
       (SourceFileInode ||
        (SourceFileInode = getActualFileInode(SourceFile)))) {
+    bool Invalid = false;
     for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
-      const SLocEntry &SLoc = getSLocEntry(I);
+      const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+      if (Invalid)
+        return SourceLocation();
+      
       if (SLoc.isFile()) { 
         const ContentCache *FileContentCache 
           = SLoc.getFile().getContentCache();

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Apr 19 19:21:03 2011
@@ -4383,8 +4383,8 @@
   return IdentifiersLoaded[ID];
 }
 
-void ASTReader::ReadSLocEntry(unsigned ID) {
-  ReadSLocEntryRecord(ID);
+bool ASTReader::ReadSLocEntry(unsigned ID) {
+  return ReadSLocEntryRecord(ID) != Success;
 }
 
 Selector ASTReader::DecodeSelector(unsigned ID) {

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue Apr 19 19:21:03 2011
@@ -2773,8 +2773,9 @@
   // Check that the FileID is invalid on the instantiation location.
   // This can manifest in invalid code.
   FileID fileID = SM.getFileID(InstLoc);
-  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID);
-  if (!sloc.isFile()) {
+  bool Invalid = false;
+  const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
+  if (!sloc.isFile() || Invalid) {
     createNullLocation(file, line, column, offset);
     return;
   }

Modified: cfe/trunk/tools/libclang/CIndexInclusionStack.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexInclusionStack.cpp?rev=129839&r1=129838&r2=129839&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexInclusionStack.cpp (original)
+++ cfe/trunk/tools/libclang/CIndexInclusionStack.cpp Tue Apr 19 19:21:03 2011
@@ -40,10 +40,10 @@
     i = 0;
   
   for ( ; i < n ; ++i) {
-
-    const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i);
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i, &Invalid);
     
-    if (!SL.isFile())
+    if (!SL.isFile() || Invalid)
       continue;
 
     const SrcMgr::FileInfo &FI = SL.getFile();





More information about the cfe-commits mailing list