forked from OSchip/llvm-project
C++1y: Add a step limit to constexpr evaluation, to catch runaway loops.
llvm-svn: 181388
This commit is contained in:
parent
1aee70b773
commit
a3d3bd215b
|
@ -83,6 +83,8 @@ def note_constexpr_depth_limit_exceeded : Note<
|
|||
"constexpr evaluation exceeded maximum depth of %0 calls">;
|
||||
def note_constexpr_call_limit_exceeded : Note<
|
||||
"constexpr evaluation hit maximum call limit">;
|
||||
def note_constexpr_step_limit_exceeded : Note<
|
||||
"constexpr evaluation hit maximum step limit; possible infinite loop?">;
|
||||
def note_constexpr_lifetime_ended : Note<
|
||||
"%select{read of|assignment to|increment of|decrement of}0 "
|
||||
"%select{temporary|variable}1 whose lifetime has ended">;
|
||||
|
|
|
@ -160,6 +160,8 @@ BENIGN_LANGOPT(InstantiationDepth, 32, 256,
|
|||
"maximum template instantiation depth")
|
||||
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
|
||||
"maximum constexpr call depth")
|
||||
BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576,
|
||||
"maximum constexpr evaluation steps")
|
||||
BENIGN_LANGOPT(BracketDepth, 32, 256,
|
||||
"maximum bracket nesting depth")
|
||||
BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
|
||||
|
|
|
@ -434,6 +434,8 @@ def ftemplate_depth : Separate<["-"], "ftemplate-depth">,
|
|||
HelpText<"Maximum depth of recursive template instantiation">;
|
||||
def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">,
|
||||
HelpText<"Maximum depth of recursive constexpr function calls">;
|
||||
def fconstexpr_steps : Separate<["-"], "fconstexpr-steps">,
|
||||
HelpText<"Maximum number of steps in constexpr function evaluation">;
|
||||
def fbracket_depth : Separate<["-"], "fbracket-depth">,
|
||||
HelpText<"Maximum nesting level for parentheses, brackets, and braces">;
|
||||
def fconst_strings : Flag<["-"], "fconst-strings">,
|
||||
|
|
|
@ -344,6 +344,7 @@ def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>;
|
|||
def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group<f_Group>;
|
||||
def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>;
|
||||
def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>;
|
||||
def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>;
|
||||
def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">,
|
||||
Group<f_Group>;
|
||||
def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>;
|
||||
|
|
|
@ -380,6 +380,11 @@ namespace {
|
|||
/// NextCallIndex - The next call index to assign.
|
||||
unsigned NextCallIndex;
|
||||
|
||||
/// StepsLeft - The remaining number of evaluation steps we're permitted
|
||||
/// to perform. This is essentially a limit for the number of statements
|
||||
/// we will evaluate.
|
||||
unsigned StepsLeft;
|
||||
|
||||
/// BottomFrame - The frame in which evaluation started. This must be
|
||||
/// initialized after CurrentCall and CallStackDepth.
|
||||
CallStackFrame BottomFrame;
|
||||
|
@ -404,9 +409,10 @@ namespace {
|
|||
bool IntOverflowCheckMode;
|
||||
|
||||
EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
|
||||
bool OverflowCheckMode=false)
|
||||
bool OverflowCheckMode = false)
|
||||
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
|
||||
CallStackDepth(0), NextCallIndex(1),
|
||||
StepsLeft(getLangOpts().ConstexprStepLimit),
|
||||
BottomFrame(*this, SourceLocation(), 0, 0, 0),
|
||||
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
|
||||
CheckingPotentialConstantExpression(false),
|
||||
|
@ -446,6 +452,15 @@ namespace {
|
|||
return (Frame->Index == CallIndex) ? Frame : 0;
|
||||
}
|
||||
|
||||
bool nextStep(const Stmt *S) {
|
||||
if (!StepsLeft) {
|
||||
Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
|
||||
return false;
|
||||
}
|
||||
--StepsLeft;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Add a diagnostic to the diagnostics list.
|
||||
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
|
||||
|
@ -530,9 +545,9 @@ namespace {
|
|||
bool keepEvaluatingAfterFailure() {
|
||||
// Should return true in IntOverflowCheckMode, so that we check for
|
||||
// overflow even if some subexpressions can't be evaluated as constants.
|
||||
return IntOverflowCheckMode ||
|
||||
(CheckingPotentialConstantExpression &&
|
||||
EvalStatus.Diag && EvalStatus.Diag->empty());
|
||||
return StepsLeft && (IntOverflowCheckMode ||
|
||||
(CheckingPotentialConstantExpression &&
|
||||
EvalStatus.Diag && EvalStatus.Diag->empty()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2794,6 +2809,9 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
|
|||
// Evaluate a statement.
|
||||
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
|
||||
const Stmt *S) {
|
||||
if (!Info.nextStep(S))
|
||||
return ESR_Failed;
|
||||
|
||||
// FIXME: Mark all temporaries in the current frame as destroyed at
|
||||
// the end of each full-expression.
|
||||
switch (S->getStmtClass()) {
|
||||
|
|
|
@ -2667,6 +2667,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
CmdArgs.push_back(A->getValue());
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
|
||||
CmdArgs.push_back("-fconstexpr-steps");
|
||||
CmdArgs.push_back(A->getValue());
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
|
||||
CmdArgs.push_back("-fbracket-depth");
|
||||
CmdArgs.push_back(A->getValue());
|
||||
|
|
|
@ -1251,6 +1251,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
|||
Diags);
|
||||
Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512,
|
||||
Diags);
|
||||
Opts.ConstexprStepLimit = Args.getLastArgIntValue(OPT_fconstexpr_steps,
|
||||
1048576, Diags);
|
||||
Opts.BracketDepth = Args.getLastArgIntValue(OPT_fbracket_depth, 256, Diags);
|
||||
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
|
||||
Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ,
|
||||
|
|
Loading…
Reference in New Issue