]> granicus.if.org Git - clang/commitdiff
Make FileEntry::getName() valid across calls to FileManager::getFile()
authorBen Langmuir <blangmuir@apple.com>
Mon, 8 Sep 2014 16:15:54 +0000 (16:15 +0000)
committerBen Langmuir <blangmuir@apple.com>
Mon, 8 Sep 2014 16:15:54 +0000 (16:15 +0000)
Because we may change the name of a FileEntry inside getFile, the name
returned by FileEntry::getName() could be destroyed.  This was causing a
use-after-free when searching the HeaderFileInfo on-disk hashtable for a
module or pch.

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

include/clang/Basic/FileManager.h
lib/Basic/FileManager.cpp

index dc9d329ab7ddb2384b381ef5909aae2534856825..5b2b022f6a3a2cf53e4bd4ffb469bb7bfffc9760 100644 (file)
@@ -59,7 +59,7 @@ public:
 /// If the 'File' member is valid, then this FileEntry has an open file
 /// descriptor for the file.
 class FileEntry {
-  std::string Name;           // Name of the file.
+  const char *Name;           // Name of the file.
   off_t Size;                 // File size in bytes.
   time_t ModTime;             // Modification time of file.
   const DirectoryEntry *Dir;  // Directory file lives in.
@@ -93,7 +93,7 @@ public:
     assert(!isValid() && "Cannot copy an initialized FileEntry");
   }
 
-  const char *getName() const { return Name.c_str(); }
+  const char *getName() const { return Name; }
   bool isValid() const { return IsValid; }
   off_t getSize() const { return Size; }
   unsigned getUID() const { return UID; }
index c0522966e38e20d5978a6746ba1ce6bf569430d7..87844864a85fbb370b6df9eb212c541524b6024f 100644 (file)
@@ -270,6 +270,19 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
   FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
 
   NamedFileEnt.setValue(&UFE);
+
+  // If the name returned by getStatValue is different than Filename, re-intern
+  // the name.
+  if (Data.Name != Filename) {
+    auto &NamedFileEnt = SeenFileEntries.GetOrCreateValue(Data.Name);
+    if (!NamedFileEnt.getValue())
+      NamedFileEnt.setValue(&UFE);
+    else
+      assert(NamedFileEnt.getValue() == &UFE &&
+             "filename from getStatValue() refers to wrong file");
+    InterndFileName = NamedFileEnt.getKeyData();
+  }
+
   if (UFE.isValid()) { // Already have an entry with this inode, return it.
 
     // FIXME: this hack ensures that if we look up a file by a virtual path in
@@ -286,13 +299,13 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
     // to switch towards a design where we return a FileName object that
     // encapsulates both the name by which the file was accessed and the
     // corresponding FileEntry.
-    UFE.Name = Data.Name;
+    UFE.Name = InterndFileName;
 
     return &UFE;
   }
 
   // Otherwise, we don't have this file yet, add it.
-  UFE.Name    = Data.Name;
+  UFE.Name    = InterndFileName;
   UFE.Size = Data.Size;
   UFE.ModTime = Data.ModTime;
   UFE.Dir     = DirInfo;