From: Ben Langmuir Date: Mon, 8 Sep 2014 16:15:54 +0000 (+0000) Subject: Make FileEntry::getName() valid across calls to FileManager::getFile() X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c7a745052faa6a061da27a49dc4c057361217d1;p=clang Make FileEntry::getName() valid across calls to FileManager::getFile() 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 --- diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index dc9d329ab7..5b2b022f6a 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -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; } diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index c0522966e3..87844864a8 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -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;