mirror of
https://github.com/intel/llvm.git
synced 2026-01-18 07:57:36 +08:00
clang/Modules: Sink CompilerInstance::KnownModules into ModuleMap
Avoid use-after-frees when FrontendAction::BeginSourceFile is called twice on the same CompilerInstance by sinking CompilerInstance::KnownModules into ModuleMap. On the way, rename the map to CachedModuleLoads. I considered (but rejected) merging this with ModuleMap::Modules, since that only has top-level modules and this map includes submodules. This is an alternative to https://reviews.llvm.org/D58497. Thanks to nemanjai for the detailed analysis of the problem!
This commit is contained in:
@@ -126,10 +126,6 @@ class CompilerInstance : public ModuleLoader {
|
||||
|
||||
std::vector<std::shared_ptr<DependencyCollector>> DependencyCollectors;
|
||||
|
||||
/// The set of top-level modules that has already been loaded,
|
||||
/// along with the module map
|
||||
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
|
||||
|
||||
/// The set of top-level modules that has already been built on the
|
||||
/// fly as part of this overall compilation action.
|
||||
std::map<std::string, std::string> BuiltModules;
|
||||
|
||||
@@ -14,17 +14,18 @@
|
||||
#ifndef LLVM_CLANG_LEX_MODULEMAP_H
|
||||
#define LLVM_CLANG_LEX_MODULEMAP_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include <ctime>
|
||||
@@ -100,6 +101,10 @@ class ModuleMap {
|
||||
/// The top-level modules that are known.
|
||||
llvm::StringMap<Module *> Modules;
|
||||
|
||||
/// Module loading cache that includes submodules, indexed by IdentifierInfo.
|
||||
/// nullptr is stored for modules that are known to fail to load.
|
||||
llvm::DenseMap<const IdentifierInfo *, Module *> CachedModuleLoads;
|
||||
|
||||
/// Shadow modules created while building this module map.
|
||||
llvm::SmallVector<Module*, 2> ShadowModules;
|
||||
|
||||
@@ -684,6 +689,16 @@ public:
|
||||
|
||||
module_iterator module_begin() const { return Modules.begin(); }
|
||||
module_iterator module_end() const { return Modules.end(); }
|
||||
|
||||
/// Cache a module load. M might be nullptr.
|
||||
void cacheModuleLoad(const IdentifierInfo &II, Module *M) {
|
||||
CachedModuleLoads[&II] = M;
|
||||
}
|
||||
|
||||
/// Return a cached module load.
|
||||
Module *getCachedModuleLoad(const IdentifierInfo &II) {
|
||||
return CachedModuleLoads.lookup(&II);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
@@ -1541,12 +1541,9 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
|
||||
}
|
||||
|
||||
void registerAll() {
|
||||
for (auto *II : LoadedModules) {
|
||||
CI.KnownModules[II] = CI.getPreprocessor()
|
||||
.getHeaderSearchInfo()
|
||||
.getModuleMap()
|
||||
.findModule(II->getName());
|
||||
}
|
||||
ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap();
|
||||
for (auto *II : LoadedModules)
|
||||
MM.cacheModuleLoad(*II, MM.findModule(II->getName()));
|
||||
LoadedModules.clear();
|
||||
}
|
||||
|
||||
@@ -1635,14 +1632,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
return LastModuleImportResult;
|
||||
}
|
||||
|
||||
clang::Module *Module = nullptr;
|
||||
|
||||
// If we don't already have information on this module, load the module now.
|
||||
llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known
|
||||
= KnownModules.find(Path[0].first);
|
||||
if (Known != KnownModules.end()) {
|
||||
// Retrieve the cached top-level module.
|
||||
Module = Known->second;
|
||||
ModuleMap &MM = getPreprocessor().getHeaderSearchInfo().getModuleMap();
|
||||
clang::Module *Module = MM.getCachedModuleLoad(*Path[0].first);
|
||||
if (Module) {
|
||||
// Nothing to do here, we found it.
|
||||
} else if (ModuleName == getLangOpts().CurrentModule) {
|
||||
// This is the module we're building.
|
||||
Module = PP->getHeaderSearchInfo().lookupModule(
|
||||
@@ -1656,7 +1650,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
// ModuleBuildFailed = true;
|
||||
// return ModuleLoadResult();
|
||||
//}
|
||||
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
|
||||
MM.cacheModuleLoad(*Path[0].first, Module);
|
||||
} else {
|
||||
// Search for a module with the given name.
|
||||
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true,
|
||||
@@ -1750,7 +1744,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt)
|
||||
<< ModuleName;
|
||||
ModuleBuildFailed = true;
|
||||
KnownModules[Path[0].first] = nullptr;
|
||||
MM.cacheModuleLoad(*Path[0].first, nullptr);
|
||||
return ModuleLoadResult();
|
||||
}
|
||||
}
|
||||
@@ -1764,7 +1758,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
// necessarily even have a module map. Since ReadAST already produces
|
||||
// diagnostics for these two cases, we simply error out here.
|
||||
ModuleBuildFailed = true;
|
||||
KnownModules[Path[0].first] = nullptr;
|
||||
MM.cacheModuleLoad(*Path[0].first, nullptr);
|
||||
return ModuleLoadResult();
|
||||
}
|
||||
|
||||
@@ -1809,7 +1803,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
"undiagnosed error in compileAndLoadModule");
|
||||
if (getPreprocessorOpts().FailedModules)
|
||||
getPreprocessorOpts().FailedModules->addFailed(ModuleName);
|
||||
KnownModules[Path[0].first] = nullptr;
|
||||
MM.cacheModuleLoad(*Path[0].first, nullptr);
|
||||
ModuleBuildFailed = true;
|
||||
return ModuleLoadResult();
|
||||
}
|
||||
@@ -1832,19 +1826,19 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
ModuleLoader::HadFatalFailure = true;
|
||||
// FIXME: The ASTReader will already have complained, but can we shoehorn
|
||||
// that diagnostic information into a more useful form?
|
||||
KnownModules[Path[0].first] = nullptr;
|
||||
MM.cacheModuleLoad(*Path[0].first, nullptr);
|
||||
return ModuleLoadResult();
|
||||
|
||||
case ASTReader::Failure:
|
||||
ModuleLoader::HadFatalFailure = true;
|
||||
// Already complained, but note now that we failed.
|
||||
KnownModules[Path[0].first] = nullptr;
|
||||
MM.cacheModuleLoad(*Path[0].first, nullptr);
|
||||
ModuleBuildFailed = true;
|
||||
return ModuleLoadResult();
|
||||
}
|
||||
|
||||
// Cache the result of this top-level module lookup for later.
|
||||
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
|
||||
MM.cacheModuleLoad(*Path[0].first, Module);
|
||||
}
|
||||
|
||||
// If we never found the module, fail.
|
||||
|
||||
Reference in New Issue
Block a user