Skip to content

Commit 0683f39

Browse files
committed
[ClangImporter] Break cycle in IAM extensions
Under a set of circumstances that I cannot fully characterize, it was possible for `ClangImporter::Implementation::importDeclContextOf()` to end up recursing until stack overflow while trying to import a global as a member. The cycle was caused by `addExtension()` using a newly-created extension’s lazy member loader to load its members before the extension had been added to ClangImporter’s `extensionPoints` table. Loading the members would try to import the IAM members again, which would cause `importDeclContextOf()` to try to create another extension to contain them, which `addExtension()` would force to load those members. Repeat until stack overflow. I have fixed this bug by registering the extension in the `extensionPoints` map before its member loader is set. This ensures that if `importDeclContextOf()` gets called for any reason after that point, it will return the existing extension instead of creating a new one, avoiding the cycle. Unfortunately, I was not able to figure out the exact conditions that were necessary to reproduce this bug, so I have not included a test. However, I have tested with the affected project locally and confirmed that this change lets it build. All existing tests pass. Fixes rdar://120854030.
1 parent 0842787 commit 0683f39

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9043,6 +9043,11 @@ ClangImporter::Implementation::importDeclContextOf(
90439043
nominal->getDeclaredType());
90449044
SwiftContext.evaluator.cacheOutput(ExtendedNominalRequest{ext},
90459045
std::move(nominal));
9046+
9047+
// Record this extension so we can find it later. We do this early because
9048+
// once we've set the member loader, we don't know when the compiler will use
9049+
// it and end up back in this method.
9050+
extensionPoints[extensionKey] = ext;
90469051
ext->setMemberLoader(this, reinterpret_cast<uintptr_t>(declSubmodule));
90479052

90489053
if (auto protoDecl = ext->getExtendedProtocolDecl()) {
@@ -9052,8 +9057,6 @@ ClangImporter::Implementation::importDeclContextOf(
90529057
// Add the extension to the nominal type.
90539058
nominal->addExtension(ext);
90549059

9055-
// Record this extension so we can find it later.
9056-
extensionPoints[extensionKey] = ext;
90579060
return ext;
90589061
}
90599062

0 commit comments

Comments
 (0)