Skip to content

Commit 761e9a0

Browse files
committed
Cache clang ASTFile information in swift::Module (NFC from the outside).
The loading of additional modules by Sema may trigger an out-of-date PCM rebuild in the Clang module dependencies of the additional module. A PCM rebuild causes the ModuleManager to unload previously loaded ASTFiles. For this reason we must use the cached ASTFile information here instead of the potentially dangling pointer to the ASTFile that is stored in the clang::Module object. This fixes a crash in IRGenDebugInfo when generation DIModule context chains. rdar://problem/47600180
1 parent 47f9dd1 commit 761e9a0

File tree

4 files changed

+73
-12
lines changed

4 files changed

+73
-12
lines changed

include/swift/ClangImporter/ClangModule.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "swift/AST/Module.h"
2020
#include "swift/ClangImporter/ClangImporter.h"
21+
#include "clang/AST/ExternalASTSource.h"
2122

2223
namespace clang {
2324
class ASTContext;
@@ -35,6 +36,8 @@ class ClangModuleUnit final : public LoadedFile {
3536
const clang::Module *clangModule;
3637
llvm::PointerIntPair<ModuleDecl *, 1, bool> adapterModule;
3738
mutable ArrayRef<ModuleDecl::ImportedModule> importedModulesForLookup;
39+
/// The metadata of the underlying Clang module.
40+
clang::ExternalASTSource::ASTSourceDescriptor ASTSourceDescriptor;
3841

3942
~ClangModuleUnit() = default;
4043

@@ -113,6 +116,11 @@ class ClangModuleUnit final : public LoadedFile {
113116

114117
clang::ASTContext &getClangASTContext() const;
115118

119+
/// Returns the ASTSourceDescriptor of the associated Clang module if one
120+
/// exists.
121+
Optional<clang::ExternalASTSource::ASTSourceDescriptor>
122+
getASTSourceDescriptor() const;
123+
116124
static bool classof(const FileUnit *file) {
117125
return file->getKind() == FileUnitKind::ClangModule;
118126
}

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3075,6 +3075,18 @@ ClangModuleUnit::ClangModuleUnit(ModuleDecl &M,
30753075
const clang::Module *clangModule)
30763076
: LoadedFile(FileUnitKind::ClangModule, M), owner(owner),
30773077
clangModule(clangModule) {
3078+
// Capture the file metadata before it goes away.
3079+
if (clangModule)
3080+
ASTSourceDescriptor = {*clangModule};
3081+
}
3082+
3083+
Optional<clang::ExternalASTSource::ASTSourceDescriptor>
3084+
ClangModuleUnit::getASTSourceDescriptor() const {
3085+
if (clangModule) {
3086+
assert(ASTSourceDescriptor.getModuleOrNull() == clangModule);
3087+
return ASTSourceDescriptor;
3088+
}
3089+
return None;
30783090
}
30793091

30803092
bool ClangModuleUnit::hasClangModule(ModuleDecl *M) {

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
#include "swift/Basic/SourceManager.h"
2929
#include "swift/Basic/Version.h"
3030
#include "swift/ClangImporter/ClangImporter.h"
31+
#include "swift/ClangImporter/ClangModule.h"
3132
#include "swift/Demangling/ManglingMacros.h"
33+
#include "swift/Serialization/SerializedModuleLoader.h"
3234
#include "swift/SIL/SILArgument.h"
3335
#include "swift/SIL/SILBasicBlock.h"
3436
#include "swift/SIL/SILDebugScope.h"
@@ -582,14 +584,18 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
582584
}
583585

584586
StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath;
585-
auto M =
587+
llvm::DIModule *M =
586588
DBuilder.createModule(Parent, Name, ConfigMacros, IncludePath, Sysroot);
587589
DIModuleCache.insert({Key, llvm::TrackingMDNodeRef(M)});
588590
return M;
589591
}
590592

591-
llvm::DIModule *
592-
getOrCreateModule(clang::ExternalASTSource::ASTSourceDescriptor Desc) {
593+
using ASTSourceDescriptor = clang::ExternalASTSource::ASTSourceDescriptor;
594+
/// Create a DIModule from a clang module or PCH.
595+
/// The clang::Module pointer is passed separately because the recursive case
596+
/// needs to fudge the AST descriptor.
597+
llvm::DIModule *getOrCreateModule(ASTSourceDescriptor Desc,
598+
const clang::Module *ClangModule) {
593599
// PCH files don't have a signature field in the control block,
594600
// but LLVM detects skeleton CUs by looking for a non-zero DWO id.
595601
// We use the lower 64 bits for debug info.
@@ -599,10 +605,24 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
599605
: ~1ULL;
600606

601607
// Handle Clang modules.
602-
if (const clang::Module *ClangModule = Desc.getModuleOrNull()) {
608+
if (ClangModule) {
603609
llvm::DIModule *Parent = nullptr;
604-
if (ClangModule->Parent)
605-
Parent = getOrCreateModule(*ClangModule->Parent);
610+
if (ClangModule->Parent) {
611+
// The loading of additional modules by Sema may trigger an out-of-date
612+
// PCM rebuild in the Clang module dependencies of the additional
613+
// module. A PCM rebuild causes the ModuleManager to unload previously
614+
// loaded ASTFiles. For this reason we must use the cached ASTFile
615+
// information here instead of the potentially dangling pointer to the
616+
// ASTFile that is stored in the clang::Module object.
617+
//
618+
// Note: The implementation here assumes that all clang submodules
619+
// belong to the same PCM file.
620+
ASTSourceDescriptor ParentDescriptor(*ClangModule->Parent);
621+
Parent = getOrCreateModule({ParentDescriptor.getModuleName(),
622+
ParentDescriptor.getPath(),
623+
Desc.getASTFile(), Desc.getSignature()},
624+
ClangModule->Parent);
625+
}
606626
return getOrCreateModule(ClangModule, Parent, Desc.getModuleName(),
607627
Desc.getPath(), Signature, Desc.getASTFile());
608628
}
@@ -612,10 +632,18 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
612632
Desc.getASTFile());
613633
};
614634

635+
static Optional<ASTSourceDescriptor> getClangModule(const ModuleDecl &M) {
636+
for (auto *FU : M.getFiles())
637+
if (auto *CMU = dyn_cast_or_null<ClangModuleUnit>(FU))
638+
if (auto Desc = CMU->getASTSourceDescriptor())
639+
return Desc;
640+
return None;
641+
}
642+
615643
llvm::DIModule *getOrCreateModule(ModuleDecl::ImportedModule IM) {
616644
ModuleDecl *M = IM.second;
617-
if (auto *ClangModule = M->findUnderlyingClangModule())
618-
return getOrCreateModule(*ClangModule);
645+
if (Optional<ASTSourceDescriptor> ModuleDesc = getClangModule(*M))
646+
return getOrCreateModule(*ModuleDesc, ModuleDesc->getModuleOrNull());
619647

620648
StringRef Path = getFilenameFromDC(M);
621649
StringRef Name = M->getName().str();
@@ -1457,8 +1485,18 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14571485
if (auto *ClangDecl = D->getClangDecl()) {
14581486
clang::ASTReader &Reader = *CI.getClangInstance().getModuleManager();
14591487
auto Idx = ClangDecl->getOwningModuleID();
1460-
if (auto Info = Reader.getSourceDescriptor(Idx))
1461-
Scope = getOrCreateModule(*Info);
1488+
auto SubModuleDesc = Reader.getSourceDescriptor(Idx);
1489+
auto TopLevelModuleDesc = getClangModule(*D->getModuleContext());
1490+
if (SubModuleDesc && TopLevelModuleDesc) {
1491+
// Describe the submodule, but substitute the cached ASTFile from
1492+
// the toplevel module. The ASTFile pointer in SubModule may be
1493+
// dangling and cant be trusted.
1494+
Scope = getOrCreateModule({SubModuleDesc->getModuleName(),
1495+
SubModuleDesc->getPath(),
1496+
TopLevelModuleDesc->getASTFile(),
1497+
TopLevelModuleDesc->getSignature()},
1498+
SubModuleDesc->getModuleOrNull());
1499+
}
14621500
}
14631501
Context = Context->getParent();
14641502
}

test/DebugInfo/test-foundation.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ class MyObject : NSObject {
1818
// LOC-CHECK: ret
1919
@objc var MyArr = NSArray()
2020
// IMPORT-CHECK: filename: "test-foundation.swift"
21-
// IMPORT-CHECK-DAG: [[FOUNDATION:[0-9]+]] = !DIModule({{.*}} name: "Foundation",{{.*}} includePath:
21+
// IMPORT-CHECK-DAG: [[FOUNDATION:[0-9]+]] = !DIModule({{.*}} name: "Foundation",{{.*}} includePath: {{.*}}Foundation.framework
22+
// IMPORT-CHECK-DAG: [[OVERLAY:[0-9]+]] = !DIModule({{.*}} name: "Foundation",{{.*}} includePath: {{.*}}Foundation.swiftmodule
2223
// IMPORT-CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "NSArray", scope: ![[NSARRAY:[0-9]+]]
2324
// IMPORT-CHECK-DAG: ![[NSARRAY]] = !DIModule(scope: ![[FOUNDATION:[0-9]+]], name: "NSArray"
24-
// IMPORT-CHECK-DAG: !DIImportedEntity(tag: DW_TAG_imported_module, {{.*}}entity: ![[FOUNDATION]]
25+
// We actually imported the Foundation SDK overlay and not the Clang module
26+
// directly.
27+
// IMPORT-CHECK-DAG: !DIImportedEntity(tag: DW_TAG_imported_module, {{.*}}entity: ![[OVERLAY]]
2528

2629
// ALLOCCTOR-CHECK: ![[F:.*]] = !DIFile(filename: "<compiler-generated>",
2730
// ALLOCCTOR-CHECK: distinct !DISubprogram(name: "init",

0 commit comments

Comments
 (0)