Skip to content

Commit df3f332

Browse files
committed
IRGen: Hide type metadata records for noncopyable types from discovery by existing runtimes.
We'd still like to try to be forwardly compatible with future runtimes that do properly handle noncopyable types, so emit them in a separate section from copyable type records for now. This should prevent `_typeByName` from letting someone get a hold of a noncopyable type's metatype as a (copyable) `Any.Type` and then trying to use it to copy uncopyable values.
1 parent 5c98a66 commit df3f332

File tree

4 files changed

+85
-31
lines changed

4 files changed

+85
-31
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,14 @@ emitGlobalList(IRGenModule &IGM, ArrayRef<llvm::WeakTrackingVH> handles,
656656

657657
void IRGenModule::emitRuntimeRegistration() {
658658
// Duck out early if we have nothing to register.
659+
// Note that we don't consider `RuntimeResolvableTypes2` here because the
660+
// current Swift runtime is unable to handle move-only types at runtime, and
661+
// we only use this runtime registration path in JIT mode, so there are no
662+
// ABI forward compatibility concerns.
663+
//
664+
// We should incorporate the types from
665+
// `RuntimeResolvableTypes2` into the list of types to register when we do
666+
// have runtime support in place.
659667
if (SwiftProtocols.empty() && ProtocolConformances.empty() &&
660668
RuntimeResolvableTypes.empty() &&
661669
(!ObjCInterop || (ObjCProtocols.empty() && ObjCClasses.empty() &&
@@ -1033,7 +1041,16 @@ void IRGenModule::addObjCClassStub(llvm::Constant *classPtr) {
10331041

10341042
void IRGenModule::addRuntimeResolvableType(GenericTypeDecl *type) {
10351043
// Collect the nominal type records we emit into a special section.
1036-
RuntimeResolvableTypes.push_back(type);
1044+
if (type->isMoveOnly()) {
1045+
// Older runtimes should not be allowed to discover noncopyable types, since
1046+
// they will try to expose them dynamically as copyable types. Record
1047+
// noncopyable type descriptors in a separate vector so that future
1048+
// noncopyable-type-aware runtimes and reflection libraries can still find
1049+
// them.
1050+
RuntimeResolvableTypes2.push_back(type);
1051+
} else {
1052+
RuntimeResolvableTypes.push_back(type);
1053+
}
10371054

10381055
if (auto nominal = dyn_cast<NominalTypeDecl>(type)) {
10391056
// As soon as the type metadata is available, all the type's conformances
@@ -4202,21 +4219,26 @@ llvm::Constant *IRGenModule::emitProtocolConformances(bool asContiguousArray) {
42024219
/// otherwise the descriptors are emitted as individual globals and nullptr is
42034220
/// returned).
42044221
llvm::Constant *IRGenModule::emitTypeMetadataRecords(bool asContiguousArray) {
4205-
if (RuntimeResolvableTypes.empty())
4222+
if (RuntimeResolvableTypes.empty()
4223+
&& RuntimeResolvableTypes2.empty())
42064224
return nullptr;
42074225

42084226
std::string sectionName;
4227+
std::string section2Name;
42094228
switch (TargetInfo.OutputObjectFormat) {
42104229
case llvm::Triple::MachO:
42114230
sectionName = "__TEXT, __swift5_types, regular";
4231+
section2Name = "__TEXT, __swift5_types2, regular";
42124232
break;
42134233
case llvm::Triple::ELF:
42144234
case llvm::Triple::Wasm:
42154235
sectionName = "swift5_type_metadata";
4236+
section2Name = "swift5_type_metadata_2";
42164237
break;
42174238
case llvm::Triple::XCOFF:
42184239
case llvm::Triple::COFF:
42194240
sectionName = ".sw5tymd$B";
4241+
section2Name = ".sw5tym2$B";
42204242
break;
42214243
case llvm::Triple::DXContainer:
42224244
case llvm::Triple::GOFF:
@@ -4276,39 +4298,50 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords(bool asContiguousArray) {
42764298
}
42774299

42784300
// In non-JIT mode, emit the type records as individual globals.
4279-
for (auto type : RuntimeResolvableTypes) {
4280-
auto ref = getTypeEntityReference(type);
4281-
4282-
std::string recordMangledName;
4283-
if (auto opaque = dyn_cast<OpaqueTypeDecl>(type)) {
4284-
recordMangledName =
4285-
LinkEntity::forOpaqueTypeDescriptorRecord(opaque).mangleAsString();
4286-
} else if (auto nominal = dyn_cast<NominalTypeDecl>(type)) {
4287-
recordMangledName =
4288-
LinkEntity::forNominalTypeDescriptorRecord(nominal).mangleAsString();
4289-
} else {
4290-
llvm_unreachable("bad type in RuntimeResolvableTypes");
4301+
4302+
auto generateGlobalTypeList = [&](ArrayRef<GenericTypeDecl *> typesList,
4303+
StringRef section) {
4304+
if (typesList.empty()) {
4305+
return;
42914306
}
4307+
4308+
for (auto type : typesList) {
4309+
auto ref = getTypeEntityReference(type);
42924310

4293-
auto var = new llvm::GlobalVariable(
4294-
Module, TypeMetadataRecordTy, /*isConstant*/ true,
4295-
llvm::GlobalValue::PrivateLinkage, /*initializer*/ nullptr,
4296-
recordMangledName);
4311+
std::string recordMangledName;
4312+
if (auto opaque = dyn_cast<OpaqueTypeDecl>(type)) {
4313+
recordMangledName =
4314+
LinkEntity::forOpaqueTypeDescriptorRecord(opaque).mangleAsString();
4315+
} else if (auto nominal = dyn_cast<NominalTypeDecl>(type)) {
4316+
recordMangledName =
4317+
LinkEntity::forNominalTypeDescriptorRecord(nominal).mangleAsString();
4318+
} else {
4319+
llvm_unreachable("bad type in RuntimeResolvableTypes");
4320+
}
42974321

4298-
auto record = generateRecord(ref, var, {0});
4299-
var->setInitializer(record);
4322+
auto var = new llvm::GlobalVariable(
4323+
Module, TypeMetadataRecordTy, /*isConstant*/ true,
4324+
llvm::GlobalValue::PrivateLinkage, /*initializer*/ nullptr,
4325+
recordMangledName);
43004326

4301-
var->setSection(sectionName);
4302-
var->setAlignment(llvm::MaybeAlign(4));
4303-
disableAddressSanitizer(*this, var);
4304-
addUsedGlobal(var);
4327+
auto record = generateRecord(ref, var, {0});
4328+
var->setInitializer(record);
43054329

4306-
if (IRGen.Opts.ConditionalRuntimeRecords) {
4307-
// Allow dead-stripping `var` (the type record) when the type (`ref`) is
4308-
// not referenced.
4309-
appendLLVMUsedConditionalEntry(var, ref.getValue());
4330+
var->setSection(section);
4331+
var->setAlignment(llvm::MaybeAlign(4));
4332+
disableAddressSanitizer(*this, var);
4333+
addUsedGlobal(var);
4334+
4335+
if (IRGen.Opts.ConditionalRuntimeRecords) {
4336+
// Allow dead-stripping `var` (the type record) when the type (`ref`) is
4337+
// not referenced.
4338+
appendLLVMUsedConditionalEntry(var, ref.getValue());
4339+
}
43104340
}
4311-
}
4341+
};
4342+
4343+
generateGlobalTypeList(RuntimeResolvableTypes, sectionName);
4344+
generateGlobalTypeList(RuntimeResolvableTypes2, section2Name);
43124345

43134346
return nullptr;
43144347
}

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,8 +1243,12 @@ class IRGenModule {
12431243
SmallVector<ProtocolDecl *, 4> SwiftProtocols;
12441244
/// List of protocol conformances to generate descriptors for.
12451245
std::vector<ConformanceDescription> ProtocolConformances;
1246-
/// List of types to generate runtime-resolvable metadata records for.
1246+
/// List of types to generate runtime-resolvable metadata records for that
1247+
/// are consumable for any Swift runtime.
12471248
SmallVector<GenericTypeDecl *, 4> RuntimeResolvableTypes;
1249+
/// List of types to generate runtime-resolvable metadata records for that
1250+
/// are consumable for any Swift runtime aware of noncopyable types.
1251+
SmallVector<GenericTypeDecl *, 4> RuntimeResolvableTypes2;
12481252
/// List of ExtensionDecls corresponding to the generated
12491253
/// categories.
12501254
SmallVector<ExtensionDecl*, 4> ObjCCategoryDecls;

stdlib/public/runtime/ImageInspectionCommon.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727
/// The Mach-O section name for the section containing protocol conformances.
2828
/// This lives within SEG_TEXT.
2929
#define MachOProtocolConformancesSection "__swift5_proto"
30-
/// The Mach-O section name for the section containing type references.
30+
/// The Mach-O section name for the section containing copyable type references.
3131
/// This lives within SEG_TEXT.
3232
#define MachOTypeMetadataRecordSection "__swift5_types"
33+
/// The Mach-O section name for the section containing additional type references.
34+
/// This lives within SEG_TEXT.
35+
#define MachOExtraTypeMetadataRecordSection "__swift5_types2"
3336
/// The Mach-O section name for the section containing dynamic replacements.
3437
/// This lives within SEG_TEXT.
3538
#define MachODynamicReplacementSection "__swift5_replace"

test/IRGen/moveonly_deinit.sil

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ struct MOSingleRefcountLikeStructNoDeinit {
130130
var x: C
131131
}
132132

133+
// Type metadata records for noncopyable types should be in a separate list
134+
// from copyable types.
135+
136+
// CHECK-LABEL: @"$s{{.*}}1CCHn" =
137+
// CHECK-SAME: section "[[COPYABLE_SECTION_NAME:[^"]+]]"
138+
139+
// CHECK-NOT: @"$s{{.*}}8MOStructVHn" = {{.*}} section "[[COPYABLE_SECTION_NAME]]"
140+
141+
// CHECK-LABEL: @"$s{{.*}}8MOStructVHn" =
142+
// CHECK-SAME: section "[[NONCOPYABLE_SECTION_NAME:[^"]+]]"
143+
144+
// CHECK-LABEL: @"$s{{.*}}6MOEnumOHn" =
145+
// CHECK-SAME: section "[[NONCOPYABLE_SECTION_NAME]]"
146+
133147
// Very large structs will use indirect conventions for their deinit.
134148

135149
@_moveOnly

0 commit comments

Comments
 (0)