Skip to content

Commit 01595d7

Browse files
committed
Check Implicit Module Names After Cache Hits
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
1 parent 8ef7220 commit 01595d7

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

clang/lib/Serialization/ModuleManager.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,38 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
132132
return Missing;
133133
}
134134

135+
// The ModuleManager's use of FileEntry nodes as the keys for its map of
136+
// loaded modules is less than ideal. Uniqueness for FileEntry nodes is
137+
// maintained by FileManager, which in turn uses inode numbers on hosts
138+
// that support that. When coupled with the module cache's proclivity for
139+
// turning over and deleting stale PCMs, this means entries for different
140+
// module files can wind up reusing the same underlying inode. When this
141+
// happens, subsequent accesses to the Modules map will disagree on the
142+
// ModuleFile associated with a given file. In general, it is not sufficient
143+
// to resolve this conundrum with a type like FileEntryRef that stores the
144+
// name of the FileEntry node on first access because of path canonicalization
145+
// issues. However, the paths constructed for implicit module builds are
146+
// fully under Clang's control. We *can*, therefore, rely on their structure
147+
// being consistent across operating systems and across subsequent accesses
148+
// to the Modules map.
149+
auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
150+
const FileEntry *Entry) -> bool {
151+
if (Kind != MK_ImplicitModule)
152+
return true;
153+
return Entry->getName() == MF->FileName;
154+
};
155+
135156
// Check whether we already loaded this module, before
136157
if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
137-
// Check the stored signature.
138-
if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
139-
return OutOfDate;
140-
141-
Module = ModuleEntry;
142-
updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
143-
return AlreadyLoaded;
158+
if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) {
159+
// Check the stored signature.
160+
if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
161+
return OutOfDate;
162+
163+
Module = ModuleEntry;
164+
updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
165+
return AlreadyLoaded;
166+
}
144167
}
145168

146169
// Allocate a new module.

0 commit comments

Comments
 (0)