Fix a race condition with the initialization of class metadata #22409
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In our initial approach for resolving metadata dependency cycles with classes, non-transitively complete superclass metadata was fetched by the subclass's metadata completion function and passed to
swift_initClassMetadata
. That could mean generating quite a lot of code in the completion function, and so we fairly recently changed it so thatswift_initClassMetadata
instead fetched the superclass metadata via a demangling. Unfortunately, the metadata demangler only fetches abstract metadata by default, and class metadata cannot be considered even non-transitively complete when its superclass reference not at that stage. If the superclass metadata is being completed on one thread, and a subclass is being completed on another, and the subclass installs the incomplete superclass metadata in its superclass field and attempts to register the subclass with the Objective-C runtime, the runtime may crash reading the incompletely-initialized superclass.The proper fix is to make
swift_initClassMetadata
fetch non-transitively complete metadata for the superclass, delaying completion if that metadata is unavailable. Unfortunately, that can't actually be implemented on top ofswift_initClassMetadata
because that function has no means of reporting an unsatisfied dependency to its caller, and we can no longer simply change its signature without worrying about a small of internal code that might still be using it. We cannot simply perform a blocking metadata request inswift_initClassMetadata
because it is deeply problematic to block within a metadata completion function. The solution is therefore to add aswift_initClassMetadata2
which has the ability to report unsatisfied dependencies. That was done in #22386; this patch builds on that by teaching the compiler to generate code to actually use it. It is therefore not safe to use this patch if you might be running on an OS that only provides the old runtime function, but that should be a temporary Apple-internal problem.Fixes rdar://47549859.
This PR includes a small fix to #22386 which has already been incorporated into #22400, the 5.0 version of that PR. It also addresses some review feedback left on #22386.