Skip to content

Commit 549693a

Browse files
committed
Reflection: Fix crash in single-payload enum layout if payload type could not be lowered
Fixes <rdar://problem/27906876>.
1 parent 3cd90a1 commit 549693a

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

include/swift/Reflection/TypeLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_REFLECTION_TYPELOWERING_H
2020

2121
#include "llvm/ADT/DenseMap.h"
22+
#include "llvm/ADT/DenseSet.h"
2223
#include "llvm/Support/Casting.h"
2324

2425
#include <iostream>
@@ -206,6 +207,7 @@ class TypeConverter {
206207
TypeRefBuilder &Builder;
207208
std::vector<std::unique_ptr<const TypeInfo>> Pool;
208209
llvm::DenseMap<const TypeRef *, const TypeInfo *> Cache;
210+
llvm::DenseSet<const TypeRef *> RecursionCheck;
209211
llvm::DenseMap<std::pair<unsigned, unsigned>,
210212
const ReferenceTypeInfo *> ReferenceCache;
211213

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -908,19 +908,23 @@ class EnumTypeInfoBuilder {
908908
Kind = RecordKind::SinglePayloadEnum;
909909
addCase(PayloadCases[0].Name, CaseTR, CaseTI);
910910

911-
// Below logic should match the runtime function
912-
// swift_initEnumValueWitnessTableSinglePayload().
913-
NumExtraInhabitants = CaseTI->getNumExtraInhabitants();
914-
if (NumExtraInhabitants >= NoPayloadCases) {
915-
// Extra inhabitants can encode all no-payload cases.
916-
NumExtraInhabitants -= NoPayloadCases;
917-
} else {
918-
// Not enough extra inhabitants for all cases. We have to add an
919-
// extra tag field.
920-
NumExtraInhabitants = 0;
921-
Size += getNumTagBytes(Size,
922-
NoPayloadCases - NumExtraInhabitants,
923-
/*payloadCases=*/1);
911+
// If we were unable to lower the payload type, do not proceed
912+
// further.
913+
if (CaseTI != nullptr) {
914+
// Below logic should match the runtime function
915+
// swift_initEnumValueWitnessTableSinglePayload().
916+
NumExtraInhabitants = CaseTI->getNumExtraInhabitants();
917+
if (NumExtraInhabitants >= NoPayloadCases) {
918+
// Extra inhabitants can encode all no-payload cases.
919+
NumExtraInhabitants -= NoPayloadCases;
920+
} else {
921+
// Not enough extra inhabitants for all cases. We have to add an
922+
// extra tag field.
923+
NumExtraInhabitants = 0;
924+
Size += getNumTagBytes(Size,
925+
NoPayloadCases - NumExtraInhabitants,
926+
/*payloadCases=*/1);
927+
}
924928
}
925929

926930
// MultiPayloadEnumImplStrategy
@@ -1213,27 +1217,29 @@ class LowerType
12131217
}
12141218

12151219
const TypeInfo *visitOpaqueTypeRef(const OpaqueTypeRef *O) {
1216-
unreachable("Can't lower opaque TypeRef");
1220+
DEBUG(std::cerr << "Can't lower opaque TypeRef");
12171221
return nullptr;
12181222
}
12191223
};
12201224

12211225
const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) {
1226+
// See if we already computed the result
12221227
auto found = Cache.find(TR);
1223-
if (found != Cache.end()) {
1224-
auto *TI = found->second;
1225-
assert(TI != nullptr && "TypeRef recursion detected");
1226-
return TI;
1227-
}
1228+
if (found != Cache.end())
1229+
return found->second;
12281230

1229-
// Detect recursion
1230-
Cache[TR] = nullptr;
1231+
// Detect invalid recursive value types (IRGen should not emit
1232+
// them in the first place, but there might be bugs)
1233+
if (!RecursionCheck.insert(TR).second) {
1234+
DEBUG(std::cerr << "TypeRef recursion detected");
1235+
return nullptr;
1236+
}
12311237

1238+
// Compute the result and cache it
12321239
auto *TI = LowerType(*this).visit(TR);
1240+
Cache[TR] = TI;
12331241

1234-
// Cache the result
1235-
if (TI != nullptr)
1236-
Cache[TR] = TI;
1242+
RecursionCheck.erase(TR);
12371243

12381244
return TI;
12391245
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: %target-build-swift %S/Inputs/ConcreteTypes.swift -parse-as-library -emit-module -emit-library -module-name TypeLowering -Xfrontend -disable-reflection-metadata -o %t/libTypesToReflect
3+
// RUN: %target-swift-reflection-dump -binary-filename %t/libTypesToReflect -binary-filename %platform-module-dir/libswiftCore.dylib -dump-type-lowering < %s | %FileCheck %s
4+
5+
// REQUIRES: objc_interop
6+
// REQUIRES: CPU=x86_64
7+
8+
V12TypeLowering11BasicStruct
9+
// CHECK: (struct TypeLowering.BasicStruct)
10+
// CHECK: Invalid lowering
11+
12+
GSqV12TypeLowering11BasicStruct_
13+
// CHECK: (bound_generic_enum Swift.Optional
14+
// CHECK: (struct TypeLowering.BasicStruct))
15+
// CHECK: Invalid lowering

0 commit comments

Comments
 (0)