aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Serialization/ModuleManager.cpp
diff options
context:
space:
mode:
authorAdrian Prantl <aprantl@apple.com>2020-09-02 13:48:44 -0700
committerAdrian Prantl <aprantl@apple.com>2020-09-02 14:16:26 -0700
commit272742a92d2443893eb98a7b3460e243e34278f9 (patch)
tree72378e2c0c92de58020e7bccd06e5bfdb1b0f0a1 /clang/lib/Serialization/ModuleManager.cpp
parent3b12e12d4b9efbdd28113da6db0f74b660257c83 (diff)
downloadllvm-272742a92d2443893eb98a7b3460e243e34278f9.zip
llvm-272742a92d2443893eb98a7b3460e243e34278f9.tar.gz
llvm-272742a92d2443893eb98a7b3460e243e34278f9.tar.bz2
Perform an extra consistency check when searching ModuleManager's
cache for implicit modules. The ModuleManager's use of FileEntry nodes as the keys for its map of loaded modules is less than ideal. Uniqueness for FileEntry nodes is maintained by FileManager, which in turn uses inode numbers on hosts that support that. When coupled with the module cache's proclivity for turning over and deleting stale PCMs, this means entries for different module files can wind up reusing the same underlying inode. When this happens, subsequent accesses to the Modules map will disagree on the ModuleFile associated with a given file. In general, it is not sufficient to resolve this conundrum with a type like FileEntryRef that stores the name of the FileEntry node on first access because of path canonicalization issues. However, the paths constructed for implicit module builds are fully under Clang's control. We *can*, therefore, rely on their structure being consistent across operating systems and across subsequent accesses to the Modules map. To mitigate the effects of inode reuse, perform an extra name check when implicit modules are returned from the cache. This has the effect of forcing reused FileEntry nodes to stomp over existing-but-stale entries in the cache, which simulates a miss - exactly the desired behavior. rdar://48443680 Patch by Robert Widmann! Differential Revision: https://reviews.llvm.org/D86823
Diffstat (limited to 'clang/lib/Serialization/ModuleManager.cpp')
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp37
1 files changed, 30 insertions, 7 deletions
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index a42ed2f..542e75e 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -132,15 +132,38 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return Missing;
}
+ // The ModuleManager's use of FileEntry nodes as the keys for its map of
+ // loaded modules is less than ideal. Uniqueness for FileEntry nodes is
+ // maintained by FileManager, which in turn uses inode numbers on hosts
+ // that support that. When coupled with the module cache's proclivity for
+ // turning over and deleting stale PCMs, this means entries for different
+ // module files can wind up reusing the same underlying inode. When this
+ // happens, subsequent accesses to the Modules map will disagree on the
+ // ModuleFile associated with a given file. In general, it is not sufficient
+ // to resolve this conundrum with a type like FileEntryRef that stores the
+ // name of the FileEntry node on first access because of path canonicalization
+ // issues. However, the paths constructed for implicit module builds are
+ // fully under Clang's control. We *can*, therefore, rely on their structure
+ // being consistent across operating systems and across subsequent accesses
+ // to the Modules map.
+ auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
+ const FileEntry *Entry) -> bool {
+ if (Kind != MK_ImplicitModule)
+ return true;
+ return Entry->getName() == MF->FileName;
+ };
+
// Check whether we already loaded this module, before
if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
- // Check the stored signature.
- if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
- return OutOfDate;
-
- Module = ModuleEntry;
- updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
- return AlreadyLoaded;
+ if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) {
+ // Check the stored signature.
+ if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
+ return OutOfDate;
+
+ Module = ModuleEntry;
+ updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
+ return AlreadyLoaded;
+ }
}
// Allocate a new module.