Skip to content

Commit 4eaa7e3

Browse files
committed
AST: Add -max-substitution-count= and -max-substitution-depth= frontend flags
1 parent f909ca6 commit 4eaa7e3

File tree

5 files changed

+40
-9
lines changed

5 files changed

+40
-9
lines changed

include/swift/AST/InFlightSubstitution.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class InFlightSubstitution {
3535
LookupConformanceFn BaselineLookupConformance;
3636
SubstOptions Options;
3737
RecursiveTypeProperties Props;
38-
unsigned RemainingCount : 16;
38+
unsigned RemainingCount : 15;
39+
unsigned InitLimit : 1;
3940
unsigned RemainingDepth : 15;
4041
unsigned LimitReached : 1;
4142

@@ -51,7 +52,7 @@ class InFlightSubstitution {
5152
ProtocolConformanceRef projectLaneFromPackConformance(
5253
PackConformance *substPackConf, unsigned level);
5354

54-
bool checkLimits();
55+
bool checkLimits(Type ty);
5556

5657
public:
5758
InFlightSubstitution(TypeSubstitutionFn substType,

include/swift/Basic/LangOptions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,14 @@ namespace swift {
612612
/// rewrite system.
613613
bool EnableRequirementMachineOpaqueArchetypes = false;
614614

615+
/// Maximum nesting depth for type substitution operations, to prevent
616+
/// runaway recursion.
617+
unsigned MaxSubstitutionDepth = 50;
618+
619+
/// Maximum step count for type substitution operations, to prevent
620+
/// runaway recursion.
621+
unsigned MaxSubstitutionCount = 2000;
622+
615623
/// Enable implicit lifetime dependence for ~Escapable return types.
616624
bool EnableExperimentalLifetimeDependenceInference = false;
617625

include/swift/Option/FrontendOptions.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,14 @@ def disable_requirement_machine_reuse : Flag<["-"], "disable-requirement-machine
474474
def enable_requirement_machine_opaque_archetypes : Flag<["-"], "enable-requirement-machine-opaque-archetypes">,
475475
HelpText<"Enable more correct opaque archetype support, which is off by default because it might fail to produce a convergent rewrite system">;
476476

477+
def max_substitution_depth : Joined<["-"], "max-substitution-depth=">,
478+
Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>,
479+
HelpText<"Set the maximum nesting depth for type substitution operations">;
480+
481+
def max_substitution_count : Joined<["-"], "max-substitution-count=">,
482+
Flags<[FrontendOption, HelpHidden, DoesNotAffectIncrementalBuild]>,
483+
HelpText<"Set the maximum step count for type substitution operations">;
484+
477485
def dump_type_witness_systems : Flag<["-"], "dump-type-witness-systems">,
478486
HelpText<"Enables dumping type witness systems from associated type inference">;
479487

lib/AST/TypeSubstitution.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,10 @@ InFlightSubstitution::InFlightSubstitution(TypeSubstitutionFn substType,
127127
BaselineLookupConformance(lookupConformance),
128128
Options(options) {
129129

130+
InitLimit = 0;
130131
LimitReached = 0;
131-
132-
// FIXME: Make these configurable
133-
RemainingCount = 1000;
134-
RemainingDepth = 20;
132+
RemainingDepth = 0;
133+
RemainingCount = 0;
135134

136135
// FIXME: Don't substitute type parameters if one of the special flags is set.
137136
Props |= RecursiveTypeProperties::HasTypeParameter;
@@ -240,7 +239,17 @@ Type InFlightSubstitution::projectLaneFromPackType(Type substType,
240239
}
241240
}
242241

243-
bool InFlightSubstitution::checkLimits() {
242+
/// Note that the type is just used to recover an ASTContext.
243+
bool InFlightSubstitution::checkLimits(Type ty) {
244+
if (!InitLimit) {
245+
auto &ctx = ty->getASTContext();
246+
247+
InitLimit = 1;
248+
RemainingCount = ctx.LangOpts.MaxSubstitutionCount;
249+
RemainingDepth = ctx.LangOpts.MaxSubstitutionDepth;
250+
return false;
251+
}
252+
244253
if (RemainingCount == 0 || RemainingDepth == 0) {
245254
LimitReached = true;
246255
return true;
@@ -263,7 +272,7 @@ Type InFlightSubstitution::substType(SubstitutableType *origType,
263272
if (shouldSubstituteOpaqueArchetypes() &&
264273
substType->hasOpaqueArchetype() &&
265274
!substType->isEqual(origType)) {
266-
if (checkLimits()) {
275+
if (checkLimits(origType)) {
267276
return ErrorType::get(substType);
268277
}
269278

@@ -304,7 +313,7 @@ InFlightSubstitution::lookupConformance(Type dependentType,
304313
if (shouldSubstituteOpaqueArchetypes() && substConfRef &&
305314
substConfRef.getType()->hasOpaqueArchetype() &&
306315
!substConfRef.getType()->isEqual(dependentType)) {
307-
if (checkLimits()) {
316+
if (checkLimits(dependentType)) {
308317
return ProtocolConformanceRef::forInvalid();
309318
}
310319
--RemainingCount;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
17581758
if (Args.hasArg(OPT_enable_requirement_machine_opaque_archetypes))
17591759
Opts.EnableRequirementMachineOpaqueArchetypes = true;
17601760

1761+
setUnsignedIntegerArgument(OPT_max_substitution_depth,
1762+
Opts.MaxSubstitutionDepth);
1763+
setUnsignedIntegerArgument(OPT_max_substitution_count,
1764+
Opts.MaxSubstitutionCount);
1765+
17611766
if (Args.hasArg(OPT_enable_experimental_lifetime_dependence_inference))
17621767
Opts.EnableExperimentalLifetimeDependenceInference = true;
17631768
if (Args.hasArg(OPT_disable_experimental_lifetime_dependence_inference))

0 commit comments

Comments
 (0)