Skip to content

Commit 178d209

Browse files
committed
ClangImporter: Use a separate CompilerInstance for canReadPCH
ClangImporter::canReadPCH has been trying to reset the main CompilerInstance back to as if it hadn't run, but there's a long tail of potential memory corruption here. One example is that it's reusing HeaderSearch, but HeaderSearch contains a ModuleMap whose SourceLocations will point into the soon-to-be-released ASTContext on the stack. Instead, just use a separate CompilerInstnace, like the rest of the ClangImporter does when it needs a different ASTContext. This fixes a few potential memory corruption bugs, and it *may* be related to the persistent "missing submodule X" problems hitting Linux bots.
1 parent 0a1d270 commit 178d209

File tree

1 file changed

+30
-50
lines changed

1 file changed

+30
-50
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -768,73 +768,53 @@ bool ClangImporter::canReadPCH(StringRef PCHFilename) {
768768
return false;
769769

770770
// FIXME: The following attempts to do an initial ReadAST invocation to verify
771-
// the PCH, without affecting the existing CompilerInstance.
771+
// the PCH, without causing trouble for the existing CompilerInstance.
772772
// Look into combining creating the ASTReader along with verification + update
773773
// if necessary, so that we can create and use one ASTReader in the common case
774774
// when there is no need for update.
775+
clang::CompilerInstance CI(Impl.Instance->getPCHContainerOperations(),
776+
&Impl.Instance->getModuleCache());
777+
auto invocation =
778+
std::make_shared<clang::CompilerInvocation>(*Impl.Invocation);
779+
invocation->getPreprocessorOpts().DisablePCHValidation = false;
780+
invocation->getPreprocessorOpts().AllowPCHWithCompilerErrors = false;
781+
invocation->getHeaderSearchOpts().ModulesValidateSystemHeaders = true;
782+
invocation->getLangOpts()->NeededByPCHOrCompilationUsesPCH = true;
783+
invocation->getLangOpts()->CacheGeneratedPCH = true;
784+
785+
// ClangImporter::create adds a remapped MemoryBuffer that we don't need
786+
// here. Moreover, it's a raw pointer owned by the preprocessor options; if
787+
// we don't clear the range then both the original and new CompilerInvocation
788+
// will try to free it.
789+
invocation->getPreprocessorOpts().RemappedFileBuffers.clear();
775790

776-
CompilerInstance &CI = *Impl.Instance;
777-
auto clangDiags = CompilerInstance::createDiagnostics(
778-
new clang::DiagnosticOptions());
791+
CI.setInvocation(std::move(invocation));
792+
CI.setTarget(&Impl.Instance->getTarget());
793+
CI.setDiagnostics(
794+
&*CompilerInstance::createDiagnostics(new clang::DiagnosticOptions()));
779795

780796
// Note: Reusing the file manager is safe; this is a component that's already
781797
// reused when building PCM files for the module cache.
782-
clang::SourceManager clangSrcMgr(*clangDiags, CI.getFileManager());
798+
CI.createSourceManager(Impl.Instance->getFileManager());
799+
auto &clangSrcMgr = CI.getSourceManager();
783800
auto FID = clangSrcMgr.createFileID(
784801
llvm::make_unique<ZeroFilledMemoryBuffer>(1, "<main>"));
785802
clangSrcMgr.setMainFileID(FID);
786803

787-
// Note: Reusing the real HeaderSearch is dangerous, but it's not easy to
788-
// copy. We put in some effort to reset it to the way it was below.
789-
clang::HeaderSearch &headerSearchInfo =
790-
CI.getPreprocessor().getHeaderSearchInfo();
791-
assert(headerSearchInfo.getExternalLookup() == nullptr &&
792-
"already configured an ASTReader");
793-
794-
// Note: Reusing the PCM cache is safe because that's already shared when
795-
// building PCM files for the module cache. Using the top-level compiler
796-
// instance as a module loader does seem a little dangerous but does not
797-
// appear to cause problems at the moment.
798-
clang::Preprocessor PP(CI.getInvocation().getPreprocessorOptsPtr(),
799-
*clangDiags,
800-
CI.getLangOpts(),
801-
clangSrcMgr,
802-
headerSearchInfo,
803-
(clang::ModuleLoader &)CI,
804-
/*IILookup=*/nullptr,
805-
/*OwnsHeaderSearch=*/false);
806-
PP.Initialize(CI.getTarget());
807-
clang::ASTContext ctx(CI.getLangOpts(), clangSrcMgr,
808-
PP.getIdentifierTable(), PP.getSelectorTable(),
809-
PP.getBuiltinInfo());
810-
811-
// Note: Reusing the PCHContainerReader or ModuleFileExtensions could be
812-
// dangerous.
813-
std::unique_ptr<clang::ASTReader> Reader(new clang::ASTReader(
814-
PP, CI.getModuleCache(), &ctx, CI.getPCHContainerReader(),
815-
CI.getFrontendOpts().ModuleFileExtensions,
816-
CI.getHeaderSearchOpts().Sysroot,
817-
/*DisableValidation*/ false,
818-
/*AllowPCHWithCompilerErrors*/ false,
819-
/*AllowConfigurationMismatch*/ false,
820-
/*ValidateSystemInputs*/ true));
821-
SWIFT_DEFER {
822-
assert(headerSearchInfo.getExternalLookup() == Reader.get() ||
823-
headerSearchInfo.getExternalLookup() == nullptr);
824-
headerSearchInfo.SetExternalLookup(nullptr);
825-
headerSearchInfo.SetExternalSource(nullptr);
826-
};
827-
ctx.InitBuiltinTypes(CI.getTarget());
804+
// Pass in TU_Complete, which is the default mode for the Preprocessor
805+
// constructor and the right one for reading a PCH.
806+
CI.createPreprocessor(clang::TU_Complete);
807+
CI.createASTContext();
808+
CI.createModuleManager();
809+
clang::ASTReader &Reader = *CI.getModuleManager();
828810

829811
auto failureCapabilities =
830812
clang::ASTReader::ARR_Missing |
831813
clang::ASTReader::ARR_OutOfDate |
832814
clang::ASTReader::ARR_VersionMismatch;
833815

834-
auto result = Reader->ReadAST(PCHFilename,
835-
clang::serialization::MK_PCH,
836-
clang::SourceLocation(),
837-
failureCapabilities);
816+
auto result = Reader.ReadAST(PCHFilename, clang::serialization::MK_PCH,
817+
clang::SourceLocation(), failureCapabilities);
838818
switch (result) {
839819
case clang::ASTReader::Success:
840820
return true;

0 commit comments

Comments
 (0)