diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Serialization/ASTBitCodes.h | 5 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 1 | ||||
-rw-r--r-- | clang/include/clang/Serialization/Module.h | 6 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ModuleManager.h | 9 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Serialization/GlobalModuleIndex.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Serialization/Module.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Serialization/ModuleManager.cpp | 18 | ||||
-rw-r--r-- | clang/test/Modules/rebuild.m | 29 |
10 files changed, 128 insertions, 4 deletions
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 26e0ecde15c..241c62e4ced 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -288,7 +288,10 @@ namespace clang { /// \brief Record code for the module map file that was used to build this /// AST file. - MODULE_MAP_FILE = 14 + MODULE_MAP_FILE = 14, + + /// \brief Record code for the signature that identifiers this AST file. + SIGNATURE = 15 }; /// \brief Record types that occur within the input-files block diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 730a257bca8..d967ec8d212 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1125,6 +1125,7 @@ private: SourceLocation ImportLoc, ModuleFile *ImportedBy, SmallVectorImpl<ImportedModule> &Loaded, off_t ExpectedSize, time_t ExpectedModTime, + serialization::ASTFileSignature ExpectedSignature, unsigned ClientLoadCapabilities); ASTReadResult ReadControlBlock(ModuleFile &F, SmallVectorImpl<ImportedModule> &Loaded, diff --git a/clang/include/clang/Serialization/Module.h b/clang/include/clang/Serialization/Module.h index a889e8b6540..f6889cfe8e1 100644 --- a/clang/include/clang/Serialization/Module.h +++ b/clang/include/clang/Serialization/Module.h @@ -97,6 +97,8 @@ public: bool isNotFound() const { return Val.getInt() == NotFound; } }; +typedef unsigned ASTFileSignature; + /// \brief Information about a module that has been loaded by the ASTReader. /// /// Each instance of the Module class corresponds to a single AST file, which @@ -152,6 +154,10 @@ public: /// \brief The file entry for the module file. const FileEntry *File; + /// \brief The signature of the module file, which may be used along with size + /// and modification time to identify this particular file. + ASTFileSignature Signature; + /// \brief Whether this module has been directly imported by the /// user. bool DirectlyImported; diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h index 96c3619510a..3d10fad0a1b 100644 --- a/clang/include/clang/Serialization/ModuleManager.h +++ b/clang/include/clang/Serialization/ModuleManager.h @@ -179,6 +179,12 @@ public: /// \param ExpectedModTime The expected modification time of the module /// file, used for validation. This will be zero if unknown. /// + /// \param ExpectedSignature The expected signature of the module file, used + /// for validation. This will be zero if unknown. + /// + /// \param ReadSignature Reads the signature from an AST file without actually + /// loading it. + /// /// \param Module A pointer to the module file if the module was successfully /// loaded. /// @@ -191,6 +197,9 @@ public: SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, + ASTFileSignature ExpectedSignature, + std::function<ASTFileSignature(llvm::BitstreamReader &)> + ReadSignature, ModuleFile *&Module, std::string &ErrorStr); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index f3181546320..80b1c2b6bcc 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2363,6 +2363,11 @@ ASTReader::ReadControlBlock(ModuleFile &F, break; } + case SIGNATURE: + assert((!F.Signature || F.Signature == Record[0]) && "signature changed"); + F.Signature = Record[0]; + break; + case IMPORTS: { // Load each of the imported PCH files. unsigned Idx = 0, N = Record.size(); @@ -2376,6 +2381,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, SourceLocation::getFromRawEncoding(Record[Idx++]); off_t StoredSize = (off_t)Record[Idx++]; time_t StoredModTime = (time_t)Record[Idx++]; + ASTFileSignature StoredSignature = Record[Idx++]; unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); @@ -2383,7 +2389,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, // Load the AST file. switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, - StoredSize, StoredModTime, + StoredSize, StoredModTime, StoredSignature, ClientLoadCapabilities)) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. @@ -3552,7 +3558,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, SmallVector<ImportedModule, 4> Loaded; switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, /*ImportedBy=*/nullptr, Loaded, - 0, 0, + 0, 0, 0, ClientLoadCapabilities)) { case Failure: case Missing: @@ -3719,6 +3725,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, return Success; } +static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile); + ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, @@ -3726,12 +3734,14 @@ ASTReader::ReadASTCore(StringRef FileName, ModuleFile *ImportedBy, SmallVectorImpl<ImportedModule> &Loaded, off_t ExpectedSize, time_t ExpectedModTime, + ASTFileSignature ExpectedSignature, unsigned ClientLoadCapabilities) { ModuleFile *M; std::string ErrorStr; ModuleManager::AddModuleResult AddResult = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy, getGeneration(), ExpectedSize, ExpectedModTime, + ExpectedSignature, readASTFileSignature, M, ErrorStr); switch (AddResult) { @@ -4029,6 +4039,34 @@ static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { } } +static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){ + BitstreamCursor Stream(StreamFile); + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + return 0; + } + + // Scan for the CONTROL_BLOCK_ID block. + if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) + return 0; + + // Scan for SIGNATURE inside the control block. + ASTReader::RecordData Record; + while (1) { + llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + if (Entry.Kind == llvm::BitstreamEntry::EndBlock || + Entry.Kind != llvm::BitstreamEntry::Record) + return 0; + + Record.clear(); + StringRef Blob; + if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob)) + return Record[0]; + } +} + /// \brief Retrieve the name of the original source file name /// directly from the AST file, without actually loading the AST /// file. diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 0681e3975d2..e39e5bb0222 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -51,6 +51,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include <algorithm> #include <cstdio> #include <string.h> @@ -862,6 +863,7 @@ void ASTWriter::WriteBlockInfoBlock() { // Control Block. BLOCK(CONTROL_BLOCK); RECORD(METADATA); + RECORD(SIGNATURE); RECORD(MODULE_NAME); RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); @@ -1092,6 +1094,14 @@ adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) { return Filename + Pos; } +static ASTFileSignature getSignature() { + while (1) { + if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber()) + return S; + // Rely on GetRandomNumber to eventually return non-zero... + } +} + /// \brief Write the control block. void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, StringRef isysroot, @@ -1121,6 +1131,11 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, getClangFullRepositoryVersion()); + // Signature + Record.clear(); + Record.push_back(getSignature()); + Stream.EmitRecord(SIGNATURE, Record); + // Module name if (WritingModule) { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); @@ -1173,6 +1188,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddSourceLocation((*M)->ImportLoc, Record); Record.push_back((*M)->File->getSize()); Record.push_back((*M)->File->getModificationTime()); + Record.push_back((*M)->Signature); const std::string &FileName = (*M)->FileName; Record.push_back(FileName.size()); Record.append(FileName.begin(), FileName.end()); diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp index f43fbaca140..121478ce052 100644 --- a/clang/lib/Serialization/GlobalModuleIndex.cpp +++ b/clang/lib/Serialization/GlobalModuleIndex.cpp @@ -591,6 +591,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { off_t StoredSize = (off_t)Record[Idx++]; time_t StoredModTime = (time_t)Record[Idx++]; + // Skip the stored signature. + // FIXME: we could read the signature out of the import and validate it. + Idx++; + // Retrieve the imported file name. unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, diff --git a/clang/lib/Serialization/Module.cpp b/clang/lib/Serialization/Module.cpp index 6f2a3c22043..6c48a41187c 100644 --- a/clang/lib/Serialization/Module.cpp +++ b/clang/lib/Serialization/Module.cpp @@ -21,7 +21,7 @@ using namespace serialization; using namespace reader; ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) - : Kind(Kind), File(nullptr), DirectlyImported(false), + : Kind(Kind), File(nullptr), Signature(0), DirectlyImported(false), Generation(Generation), SizeInBits(0), LocalNumSLocEntries(0), SLocEntryBaseID(0), SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr), diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index 20249e0a7bd..300ef31b590 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -57,6 +57,9 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, + ASTFileSignature ExpectedSignature, + std::function<ASTFileSignature(llvm::BitstreamReader &)> + ReadSignature, ModuleFile *&Module, std::string &ErrorStr) { Module = nullptr; @@ -130,6 +133,21 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, // Initialize the stream New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), (const unsigned char *)New->Buffer->getBufferEnd()); + + if (ExpectedSignature) { + New->Signature = ReadSignature(New->StreamFile); + if (New->Signature != ExpectedSignature) { + ErrorStr = New->Signature ? "signature mismatch" + : "could not read module signature"; + + // Remove the module file immediately, since removeModules might try to + // invalidate the file cache for Entry, and that is not safe if this + // module is *itself* up to date, but has an out-of-date importer. + Modules.erase(Entry); + Chain.pop_back(); + return OutOfDate; + } + } } if (ImportedBy) { diff --git a/clang/test/Modules/rebuild.m b/clang/test/Modules/rebuild.m new file mode 100644 index 00000000000..c6e7920339e --- /dev/null +++ b/clang/test/Modules/rebuild.m @@ -0,0 +1,29 @@ +// REQUIRES: shell +// RUN: rm -rf %t + +// Build Module and set its timestamp +// RUN: echo '@import Module;' | %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs -x objective-c - +// RUN: touch -m -a -t 201101010000 %t/Module.pcm +// RUN: cp %t/Module.pcm %t/Module.pcm.saved +// RUN: wc -c %t/Module.pcm > %t/Module.size.saved + +// Build DependsOnModule +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s +// RUN: diff %t/Module.pcm %t/Module.pcm.saved +// RUN: cp %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved + +// Rebuild Module, reset its timestamp, and verify its size hasn't changed +// RUN: rm %t/Module.pcm +// RUN: echo '@import Module;' | %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs -x objective-c - +// RUN: touch -m -a -t 201101010000 %t/Module.pcm +// RUN: wc -c %t/Module.pcm > %t/Module.size +// RUN: diff %t/Module.size %t/Module.size.saved +// RUN: cp %t/Module.pcm %t/Module.pcm.saved.2 + +// But the signature at least is expected to change, so we rebuild DependsOnModule. +// NOTE: if we change how the signature is created, this test may need updating. +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fdisable-module-hash -fsyntax-only -F %S/Inputs %s +// RUN: diff %t/Module.pcm %t/Module.pcm.saved.2 +// RUN: not diff %t/DependsOnModule.pcm %t/DependsOnModule.pcm.saved + +@import DependsOnModule; |