[PCH] For HeaderFileInfoTrait, hash the key using size & time of the file.

Previously the hash would be the filename portion of the path, which could be
different for a filename with different case or a symbolic link with a different
name completely.
This did not actually create any issue so far because by validating all headers
in the PCH we created uniqued FileEntries based on inodes, so an #include of
a symbolic link (refering to a file from the PCH) would end up with a FileEntry
with filename same as the one recorded in the PCH.

llvm-svn: 176566
This commit is contained in:
Argyrios Kyrtzidis 2013-03-06 18:12:47 +00:00
parent 61a3896d9f
commit 5c2a345e48
3 changed files with 66 additions and 40 deletions

View File

@ -41,6 +41,7 @@
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "clang/Serialization/SerializationDiagnostic.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/ErrorHandling.h"
@ -1294,24 +1295,28 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const
return LocalID + I->second;
}
unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
return llvm::HashString(llvm::sys::path::filename(path));
unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
FE->getName() };
return ikey;
}
bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
if (strcmp(a, b) == 0)
return true;
if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
if (strcmp(a.Filename, b.Filename) == 0)
return true;
// Determine whether the actual files are equivalent.
FileManager &FileMgr = Reader.getFileManager();
const FileEntry *FEA = FileMgr.getFile(a);
const FileEntry *FEB = FileMgr.getFile(b);
const FileEntry *FEA = FileMgr.getFile(a.Filename);
const FileEntry *FEB = FileMgr.getFile(b.Filename);
return (FEA && FEA == FEB);
}
@ -1319,11 +1324,20 @@ std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
unsigned DataLen = (unsigned) *d++;
return std::make_pair(KeyLen + 1, DataLen);
return std::make_pair(KeyLen, DataLen);
}
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
internal_key_type ikey;
ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
ikey.Filename = (const char *)d;
return ikey;
}
HeaderFileInfoTrait::data_type
HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
HeaderFileInfoTrait::ReadData(internal_key_ref, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
using namespace clang::io;
@ -4109,7 +4123,7 @@ namespace {
return false;
// Look in the on-disk hash table for an entry for this file name.
HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName());
HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
if (Pos == Table->end())
return false;

View File

@ -25,6 +25,7 @@ namespace clang {
class ASTReader;
class HeaderSearch;
struct HeaderFileInfo;
class FileEntry;
namespace serialization {
@ -198,8 +199,14 @@ class HeaderFileInfoTrait {
const char *FrameworkStrings;
public:
typedef const char *external_key_type;
typedef const char *internal_key_type;
typedef const FileEntry *external_key_type;
struct internal_key_type {
off_t Size;
time_t ModTime;
const char *Filename;
};
typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
@ -207,19 +214,16 @@ public:
const char *FrameworkStrings)
: Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
static unsigned ComputeHash(const char *path);
static internal_key_type GetInternalKey(const char *path);
bool EqualKey(internal_key_type a, internal_key_type b);
static unsigned ComputeHash(internal_key_ref ikey);
static internal_key_type GetInternalKey(const FileEntry *FE);
bool EqualKey(internal_key_ref a, internal_key_ref b);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
static internal_key_type ReadKey(const unsigned char *d, unsigned) {
return (const char *)d;
}
static internal_key_type ReadKey(const unsigned char *d, unsigned);
data_type ReadData(const internal_key_type, const unsigned char *d,
unsigned DataLen);
data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);
};
/// \brief The on-disk hash table used for known header files.

View File

@ -42,6 +42,7 @@
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/FileSystem.h"
@ -1372,32 +1373,38 @@ namespace {
HeaderFileInfoTrait(ASTWriter &Writer)
: Writer(Writer) { }
typedef const char *key_type;
typedef key_type key_type_ref;
struct key_type {
const FileEntry *FE;
const char *Filename;
};
typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
static unsigned ComputeHash(const char *path) {
// The hash is based only on the filename portion of the key, so that the
// reader can match based on filenames when symlinking or excess path
// elements ("foo/../", "../") change the form of the name. However,
// complete path is still the key.
return llvm::HashString(llvm::sys::path::filename(path));
static unsigned ComputeHash(key_type_ref key) {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
return llvm::hash_combine(key.FE->getSize(),
key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, const char *path,
data_type_ref Data) {
unsigned StrLen = strlen(path);
clang::io::Emit16(Out, StrLen);
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
clang::io::Emit16(Out, KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
clang::io::Emit8(Out, DataLen);
return std::make_pair(StrLen + 1, DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
Out.write(path, KeyLen);
void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
clang::io::Emit64(Out, key.FE->getSize());
KeyLen -= 8;
clang::io::Emit64(Out, key.FE->getModificationTime());
KeyLen -= 8;
Out.write(key.Filename, KeyLen);
}
void EmitData(raw_ostream &Out, key_type_ref,
@ -1479,7 +1486,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SavedStrings.push_back(Filename);
}
Generator.insert(Filename, HFI, GeneratorTrait);
HeaderFileInfoTrait::key_type key = { File, Filename };
Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}