Skip to content

Commit 4945a56

Browse files
committed
[Reflection] Put a recursion limit on readTypeFromMetadata.
We can end up with a stack overflow if we encounter a very deeply nested type, or bad data that looks like one. Fail gracefully for types that are nested beyond a limit. By default, the limit is 50. rdar://100847548
1 parent 8a95701 commit 4945a56

File tree

2 files changed

+89
-24
lines changed

2 files changed

+89
-24
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ class MetadataReader {
186186
using StoredSize = typename Runtime::StoredSize;
187187
using TargetClassMetadata = TargetClassMetadataType<Runtime>;
188188

189+
static const int defaultTypeRecursionLimit = 50;
190+
189191
private:
190192
/// The maximum number of bytes to read when reading metadata. Anything larger
191193
/// will automatically return failure. This prevents us from reading absurd
@@ -803,12 +805,25 @@ class MetadataReader {
803805
}
804806

805807
/// Given a remote pointer to metadata, attempt to turn it into a type.
806-
BuiltType readTypeFromMetadata(StoredPointer MetadataAddress,
807-
bool skipArtificialSubclasses = false) {
808+
BuiltType
809+
readTypeFromMetadata(StoredPointer MetadataAddress,
810+
bool skipArtificialSubclasses = false,
811+
int recursion_limit = defaultTypeRecursionLimit) {
808812
auto Cached = TypeCache.find(MetadataAddress);
809813
if (Cached != TypeCache.end())
810814
return Cached->second;
811815

816+
if (recursion_limit <= 0) {
817+
return nullptr;
818+
}
819+
820+
// readTypeFromMetadata calls out to various other functions which can call
821+
// back to readTypeFromMetadata. We only want to bump the recursion limit
822+
// down here, not in the other functions, so that we're only counting
823+
// recursive calls to readTypeFromMetadata. This decrement is the only place
824+
// where we'll subtract 1.
825+
recursion_limit--;
826+
812827
// If we see garbage data in the process of building a BuiltType, and get
813828
// the same metadata address again, we will hit an infinite loop.
814829
// Insert a negative result into the cache now so that, if we recur with
@@ -821,11 +836,12 @@ class MetadataReader {
821836

822837
switch (Meta->getKind()) {
823838
case MetadataKind::Class:
824-
return readNominalTypeFromClassMetadata(Meta, skipArtificialSubclasses);
839+
return readNominalTypeFromClassMetadata(Meta, recursion_limit,
840+
skipArtificialSubclasses);
825841
case MetadataKind::Struct:
826842
case MetadataKind::Enum:
827843
case MetadataKind::Optional:
828-
return readNominalTypeFromMetadata(Meta);
844+
return readNominalTypeFromMetadata(Meta, recursion_limit);
829845
case MetadataKind::Tuple: {
830846
auto tupleMeta = cast<TargetTupleTypeMetadata<Runtime>>(Meta);
831847

@@ -834,7 +850,8 @@ class MetadataReader {
834850

835851
for (unsigned i = 0, n = tupleMeta->NumElements; i != n; ++i) {
836852
auto &element = tupleMeta->getElement(i);
837-
if (auto elementType = readTypeFromMetadata(element.Type))
853+
if (auto elementType =
854+
readTypeFromMetadata(element.Type, false, recursion_limit))
838855
elementTypes.push_back(elementType);
839856
else
840857
return BuiltType();
@@ -856,7 +873,8 @@ class MetadataReader {
856873

857874
std::vector<FunctionParam<BuiltType>> Parameters;
858875
for (unsigned i = 0, n = Function->getNumParameters(); i != n; ++i) {
859-
auto ParamTypeRef = readTypeFromMetadata(Function->getParameter(i));
876+
auto ParamTypeRef = readTypeFromMetadata(Function->getParameter(i),
877+
false, recursion_limit);
860878
if (!ParamTypeRef)
861879
return BuiltType();
862880

@@ -866,7 +884,8 @@ class MetadataReader {
866884
Parameters.push_back(std::move(Param));
867885
}
868886

869-
auto Result = readTypeFromMetadata(Function->ResultType);
887+
auto Result =
888+
readTypeFromMetadata(Function->ResultType, false, recursion_limit);
870889
if (!Result)
871890
return BuiltType();
872891

@@ -880,7 +899,8 @@ class MetadataReader {
880899

881900
BuiltType globalActor = BuiltType();
882901
if (Function->hasGlobalActor()) {
883-
globalActor = readTypeFromMetadata(Function->getGlobalActor());
902+
globalActor = readTypeFromMetadata(Function->getGlobalActor(), false,
903+
recursion_limit);
884904
if (globalActor)
885905
flags = flags.withGlobalActor(true);
886906
}
@@ -915,7 +935,8 @@ class MetadataReader {
915935
BuiltType SuperclassType = BuiltType();
916936
if (Exist->Flags.hasSuperclassConstraint()) {
917937
// The superclass is stored after the list of protocols.
918-
SuperclassType = readTypeFromMetadata(Exist->getSuperclassConstraint());
938+
SuperclassType = readTypeFromMetadata(Exist->getSuperclassConstraint(),
939+
false, recursion_limit);
919940
if (!SuperclassType) return BuiltType();
920941

921942
HasExplicitAnyObject = true;
@@ -971,7 +992,7 @@ class MetadataReader {
971992
std::vector<BuiltType> builtArgs;
972993
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
973994
auto remoteArg = Exist->getGeneralizationArguments()[i];
974-
auto builtArg = readTypeFromMetadata(remoteArg);
995+
auto builtArg = readTypeFromMetadata(remoteArg, false, recursion_limit);
975996
if (!builtArg)
976997
return BuiltType();
977998
builtArgs.push_back(builtArg);
@@ -1036,7 +1057,8 @@ class MetadataReader {
10361057

10371058
case MetadataKind::Metatype: {
10381059
auto Metatype = cast<TargetMetatypeMetadata<Runtime>>(Meta);
1039-
auto Instance = readTypeFromMetadata(Metatype->InstanceType);
1060+
auto Instance =
1061+
readTypeFromMetadata(Metatype->InstanceType, false, recursion_limit);
10401062
if (!Instance) return BuiltType();
10411063
auto BuiltMetatype = Builder.createMetatypeType(Instance);
10421064
TypeCache[MetadataAddress] = BuiltMetatype;
@@ -1056,7 +1078,8 @@ class MetadataReader {
10561078
}
10571079
case MetadataKind::ExistentialMetatype: {
10581080
auto Exist = cast<TargetExistentialMetatypeMetadata<Runtime>>(Meta);
1059-
auto Instance = readTypeFromMetadata(Exist->InstanceType);
1081+
auto Instance =
1082+
readTypeFromMetadata(Exist->InstanceType, false, recursion_limit);
10601083
if (!Instance) return BuiltType();
10611084
auto BuiltExist = Builder.createExistentialMetatypeType(Instance);
10621085
TypeCache[MetadataAddress] = BuiltExist;
@@ -2948,8 +2971,9 @@ class MetadataReader {
29482971
// TODO: We need to be able to produce protocol conformances for each
29492972
// substitution type as well in order to accurately rebuild bound generic
29502973
// types or types in protocol-constrained inner contexts.
2951-
std::vector<BuiltType>
2952-
getGenericSubst(MetadataRef metadata, ContextDescriptorRef descriptor) {
2974+
std::vector<BuiltType> getGenericSubst(MetadataRef metadata,
2975+
ContextDescriptorRef descriptor,
2976+
int recursion_limit) {
29532977
auto generics = descriptor->getGenericContext();
29542978
if (!generics)
29552979
return {};
@@ -2986,8 +3010,8 @@ class MetadataReader {
29863010
return {};
29873011
}
29883012
genericArgsAddr += sizeof(StoredPointer);
2989-
2990-
auto builtArg = readTypeFromMetadata(arg);
3013+
3014+
auto builtArg = readTypeFromMetadata(arg, false, recursion_limit);
29913015
if (!builtArg)
29923016
return {};
29933017
builtSubsts.push_back(builtArg);
@@ -3007,8 +3031,10 @@ class MetadataReader {
30073031
return builtSubsts;
30083032
}
30093033

3010-
BuiltType readNominalTypeFromMetadata(MetadataRef origMetadata,
3011-
bool skipArtificialSubclasses = false) {
3034+
BuiltType
3035+
readNominalTypeFromMetadata(MetadataRef origMetadata,
3036+
int recursion_limit = defaultTypeRecursionLimit,
3037+
bool skipArtificialSubclasses = false) {
30123038
auto metadata = origMetadata;
30133039
auto descriptorAddress =
30143040
readAddressOfNominalTypeDescriptor(metadata,
@@ -3038,7 +3064,8 @@ class MetadataReader {
30383064
BuiltType nominal;
30393065
if (descriptor->isGeneric()) {
30403066
// Resolve the generic arguments.
3041-
auto builtGenerics = getGenericSubst(metadata, descriptor);
3067+
auto builtGenerics =
3068+
getGenericSubst(metadata, descriptor, recursion_limit);
30423069
if (builtGenerics.empty())
30433070
return BuiltType();
30443071
nominal = Builder.createBoundGenericType(typeDecl, builtGenerics);
@@ -3060,11 +3087,14 @@ class MetadataReader {
30603087
return nominal;
30613088
}
30623089

3063-
BuiltType readNominalTypeFromClassMetadata(MetadataRef origMetadata,
3064-
bool skipArtificialSubclasses = false) {
3090+
BuiltType
3091+
readNominalTypeFromClassMetadata(MetadataRef origMetadata,
3092+
int recursion_limit,
3093+
bool skipArtificialSubclasses = false) {
30653094
auto classMeta = cast<TargetClassMetadata>(origMetadata);
30663095
if (classMeta->isTypeMetadata())
3067-
return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses);
3096+
return readNominalTypeFromMetadata(origMetadata, recursion_limit,
3097+
skipArtificialSubclasses);
30683098

30693099
std::string className;
30703100
auto origMetadataPtr = getAddress(origMetadata);
@@ -3077,8 +3107,9 @@ class MetadataReader {
30773107
if (!stripSignedPointer(classMeta->Superclass))
30783108
return BuiltType();
30793109

3080-
BuiltObjCClass = readTypeFromMetadata(
3081-
stripSignedPointer(classMeta->Superclass), skipArtificialSubclasses);
3110+
BuiltObjCClass =
3111+
readTypeFromMetadata(stripSignedPointer(classMeta->Superclass),
3112+
skipArtificialSubclasses, recursion_limit);
30823113
}
30833114

30843115
TypeCache[origMetadataPtr] = BuiltObjCClass;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -g -lswiftSwiftReflectionTest %s -o %t/reflect_deep_generic
3+
// RUN: %target-codesign %t/reflect_deep_generic
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_deep_generic | %FileCheck %s
6+
7+
// REQUIRES: reflection_test_support
8+
// REQUIRES: executable_test
9+
// UNSUPPORTED: use_os_stdlib
10+
11+
import SwiftReflectionTest
12+
13+
protocol Nester {
14+
func nest() -> Nester
15+
}
16+
17+
class C<T>: Nester {
18+
func nest() -> Nester {
19+
return C<Self>()
20+
}
21+
}
22+
23+
var nester: Nester = C<Int>()
24+
for _ in 0..<10000 {
25+
nester = nester.nest()
26+
}
27+
28+
// This will fail due to the excessively nested type, but we're making sure it
29+
// fails gracefully and doesn't crash.
30+
reflect(object: nester as AnyObject)
31+
32+
doneReflecting()
33+
34+
// CHECK: Done.

0 commit comments

Comments
 (0)