Skip to content

Commit b48b786

Browse files
authored
Merge pull request swiftlang#28679 from CodaFi/latent-semantic-mapping
[ClangImporter] Block Re-Entrancy In Lookups
2 parents bfbd893 + 4a3bb30 commit b48b786

File tree

3 files changed

+110
-30
lines changed

3 files changed

+110
-30
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,12 +2962,36 @@ void ClangImporter::loadExtensions(NominalTypeDecl *nominal,
29622962
// For an Objective-C class, import all of the visible categories.
29632963
if (auto objcClass = dyn_cast_or_null<clang::ObjCInterfaceDecl>(
29642964
effectiveClangContext.getAsDeclContext())) {
2965+
SmallVector<clang::NamedDecl *, 4> DelayedCategories;
2966+
29652967
// Simply importing the categories adds them to the list of extensions.
29662968
for (auto I = objcClass->visible_categories_begin(),
29672969
E = objcClass->visible_categories_end();
29682970
I != E; ++I) {
2971+
// Delay installing categories that don't have an owning module.
2972+
if (!I->hasOwningModule()) {
2973+
DelayedCategories.push_back(*I);
2974+
continue;
2975+
}
2976+
29692977
Impl.importDeclReal(*I, Impl.CurrentVersion);
29702978
}
2979+
2980+
// Install all the delayed categories.
2981+
//
2982+
// The very notion of a delayed category is a result of an emergent behavior
2983+
// of the visible categories list and the order we import modules. The list
2984+
// appears in deserialization order rather than some "source order", so it's
2985+
// possible for, say, a bridging header to import a module that defines an
2986+
// interface and some categories, but for the categories in the bridging
2987+
// header to appear *before* the categories in the module - the imported
2988+
// module will be deserialized on demand. We take it on faith that if there
2989+
// is no owning module for a given category, that it was created in such a
2990+
// way, and thus we install it last to try to emulate what we want
2991+
// "source order" to mean.
2992+
for (const auto *DelayedCat : DelayedCategories) {
2993+
Impl.importDeclReal(DelayedCat, Impl.CurrentVersion);
2994+
}
29712995
}
29722996

29732997
// Dig through each of the Swift lookup tables, creating extensions
@@ -3690,6 +3714,24 @@ void ClangImporter::Implementation::lookupAllObjCMembers(
36903714
}
36913715
}
36923716

3717+
// Force the named member of the entire inheritance hierarchy to be loaded and
3718+
// deserialized before loading the named member of this class. This allows the
3719+
// decl members table to be warmed up and enables the correct identification of
3720+
// overrides.
3721+
static void loadNamedMemberOfSuperclassesIfNeeded(const ClassDecl *CD,
3722+
DeclBaseName name) {
3723+
if (!CD)
3724+
return;
3725+
3726+
while ((CD = CD->getSuperclassDecl())) {
3727+
if (CD->hasClangNode()) {
3728+
auto ci = CD->getASTContext().getOrCreateLazyIterableContextData(
3729+
CD, /*lazyLoader=*/nullptr);
3730+
ci->loader->loadNamedMembers(CD, name, ci->memberData);
3731+
}
3732+
}
3733+
}
3734+
36933735
Optional<TinyPtrVector<ValueDecl *>>
36943736
ClangImporter::Implementation::loadNamedMembers(
36953737
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {
@@ -3751,6 +3793,8 @@ ClangImporter::Implementation::loadNamedMembers(
37513793

37523794
assert(isa<clang::ObjCContainerDecl>(CD) || isa<clang::NamespaceDecl>(CD));
37533795

3796+
loadNamedMemberOfSuperclassesIfNeeded(dyn_cast<ClassDecl>(D), N);
3797+
37543798
TinyPtrVector<ValueDecl *> Members;
37553799
for (auto entry : table->lookup(SerializedSwiftName(N),
37563800
effectiveClangContext)) {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,13 @@ namespace {
21742174
return getVersion() == getActiveSwiftVersion();
21752175
}
21762176

2177+
template <typename T>
2178+
T *recordMemberInContext(DeclContext *dc, T *member) {
2179+
assert(member && "Attempted to record null member!");
2180+
Impl.MembersForNominal[dc->getSelfNominalTypeDecl()].push_back(member);
2181+
return member;
2182+
}
2183+
21772184
/// Import the name of the given entity.
21782185
///
21792186
/// This version of importFullName introduces any context-specific
@@ -3734,7 +3741,7 @@ namespace {
37343741
if (correctSwiftName)
37353742
markAsVariant(result, *correctSwiftName);
37363743

3737-
return result;
3744+
return recordMemberInContext(dc, result);
37383745
}
37393746

37403747
void finishFuncDecl(const clang::FunctionDecl *decl,
@@ -4344,7 +4351,7 @@ namespace {
43444351
}
43454352
}
43464353

4347-
return result;
4354+
return recordMemberInContext(dc, result);
43484355
}
43494356

43504357
public:
@@ -5002,44 +5009,55 @@ namespace {
50025009
return nullptr;
50035010

50045011
VarDecl *overridden = nullptr;
5005-
if (dc->getSelfClassDecl()) {
5006-
// Check whether there is a function with the same name as this
5007-
// property. If so, suppress the property; the user will have to use
5008-
// the methods directly, to avoid ambiguities.
5009-
NominalTypeDecl *lookupContext = dc->getSelfNominalTypeDecl();
5012+
// Check whether there is a function with the same name as this
5013+
// property. If so, suppress the property; the user will have to use
5014+
// the methods directly, to avoid ambiguities.
5015+
if (auto *subject = dc->getSelfClassDecl()) {
5016+
bool foundMethod = false;
50105017

50115018
if (auto *classDecl = dyn_cast<ClassDecl>(dc)) {
5012-
// If we're importing into the primary @interface for something, as
5013-
// opposed to an extension, make sure we don't try to load any
5014-
// categories...by just looking into the super type.
5015-
lookupContext = classDecl->getSuperclassDecl();
5019+
// Start looking into the superclass.
5020+
subject = classDecl->getSuperclassDecl();
50165021
}
50175022

5018-
if (lookupContext) {
5019-
SmallVector<ValueDecl *, 2> lookup;
5020-
dc->lookupQualified(lookupContext, DeclNameRef(name),
5021-
NL_QualifiedDefault | NL_KnownNoDependency,
5022-
lookup);
5023-
bool foundMethod = false;
5024-
for (auto result : lookup) {
5025-
if (isa<FuncDecl>(result) &&
5026-
result->isInstanceMember() == decl->isInstanceProperty() &&
5027-
result->getFullName().getArgumentNames().empty())
5028-
foundMethod = true;
5029-
5030-
if (auto var = dyn_cast<VarDecl>(result)) {
5023+
for (; subject; (subject = subject->getSuperclassDecl())) {
5024+
llvm::SmallVector<ValueDecl *, 8> lookup;
5025+
auto found = Impl.MembersForNominal.find(subject);
5026+
if (found != Impl.MembersForNominal.end()) {
5027+
lookup.append(found->second.begin(), found->second.end());
5028+
namelookup::pruneLookupResultSet(dc, NL_QualifiedDefault, lookup);
5029+
}
5030+
5031+
for (auto *&result : lookup) {
5032+
// Skip declarations that don't match the name we're looking for.
5033+
if (result->getBaseName() != name)
5034+
continue;
5035+
5036+
if (auto *fd = dyn_cast<FuncDecl>(result)) {
5037+
if (fd->isInstanceMember() != decl->isInstanceProperty())
5038+
continue;
5039+
5040+
if (fd->getFullName().getArgumentNames().empty()) {
5041+
foundMethod = true;
5042+
}
5043+
} else {
5044+
auto *var = cast<VarDecl>(result);
5045+
if (var->isInstanceMember() != decl->isInstanceProperty())
5046+
continue;
5047+
50315048
// If the selectors of the getter match in Objective-C, we have an
50325049
// override.
5033-
if (var->isInstanceMember() == decl->isInstanceProperty() &&
5034-
var->getObjCGetterSelector() ==
5035-
Impl.importSelector(decl->getGetterName()))
5050+
if (var->getObjCGetterSelector() ==
5051+
Impl.importSelector(decl->getGetterName())) {
50365052
overridden = var;
5053+
}
50375054
}
50385055
}
5039-
if (foundMethod && !overridden)
5040-
return nullptr;
50415056
}
50425057

5058+
if (foundMethod && !overridden)
5059+
return nullptr;
5060+
50435061
if (overridden) {
50445062
const DeclContext *overrideContext = overridden->getDeclContext();
50455063
// It's okay to compare interface types directly because Objective-C
@@ -5130,7 +5148,7 @@ namespace {
51305148
if (correctSwiftName)
51315149
markAsVariant(result, *correctSwiftName);
51325150

5133-
return result;
5151+
return recordMemberInContext(dc, result);
51345152
}
51355153

51365154
Decl *
@@ -8405,6 +8423,19 @@ createUnavailableDecl(Identifier name, DeclContext *dc, Type type,
84058423
return var;
84068424
}
84078425

8426+
// Force the members of the entire inheritance hierarchy to be loaded and
8427+
// deserialized before loading the members of this class. This allows the
8428+
// decl members table to be warmed up and enables the correct identification of
8429+
// overrides.
8430+
static void loadAllMembersOfSuperclassesIfNeeded(const ClassDecl *CD) {
8431+
if (!CD)
8432+
return;
8433+
8434+
while ((CD = CD->getSuperclassDecl())) {
8435+
if (CD->hasClangNode())
8436+
CD->loadAllMembers();
8437+
}
8438+
}
84088439

84098440
void
84108441
ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
@@ -8418,6 +8449,7 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
84188449

84198450
// If not, we're importing globals-as-members into an extension.
84208451
if (objcContainer) {
8452+
loadAllMembersOfSuperclassesIfNeeded(dyn_cast<ClassDecl>(D));
84218453
loadAllMembersOfObjcContainer(D, objcContainer);
84228454
return;
84238455
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
447447
// Mapping from imported types to their raw value types.
448448
llvm::DenseMap<const NominalTypeDecl *, Type> RawTypes;
449449

450+
/// Keep track of all member declarations that have been imported into a nominal type.
451+
llvm::DenseMap<const NominalTypeDecl *, std::vector<ValueDecl *>>
452+
MembersForNominal;
453+
450454
clang::CompilerInstance *getClangInstance() {
451455
return Instance.get();
452456
}

0 commit comments

Comments
 (0)