On Thu, Mar 7, 2019 at 8:22 PM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > We have -fconstexpr-loop-limit= option to have an upper bound for constexpr > evaluation of a single loop. Even with that limit in place, if we have > several nested loops during constexpr evaluation, even when each could have > a few hundred iterations, the whole loop nest could take years to evaluate. > And the loops can be split across several constexpr function calls even. > > The following patch adds another, slightly larger, limit on total number of > iterations in the whole loop nest. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Shouldn't we somehow limit the number of stmt evaluations instead? I can imagine using constexpr templates you can do "loops" easily without actually writing loops ... Richard. > 2019-03-07 Jakub Jelinek <ja...@redhat.com> > > PR c++/87481 > * doc/invoke.texi (-fconstexpr-loop-nest-limit=): Document. > (-fconstexpr-loop-limit=): Slightly adjust wording. > > * c.opt (-fconstexpr-loop-nest-limit=): New option. > (-fconstexpr-loop-limit=): Slightly adjust description. > > * constexpr.c (cxx_eval_loop_expr): Count also number of iterations > of all nested loops and punt if it is above constexpr_loop_nest_limit. > > * g++.dg/cpp1y/constexpr-87481.C: New test. > > --- gcc/doc/invoke.texi.jj 2019-03-02 09:03:25.822755663 +0100 > +++ gcc/doc/invoke.texi 2019-03-07 14:25:34.881197149 +0100 > @@ -210,7 +210,7 @@ in the following sections. > @gccoptlist{-fabi-version=@var{n} -fno-access-control @gol > -faligned-new=@var{n} -fargs-in-order=@var{n} -fchar8_t -fcheck-new @gol > -fconstexpr-depth=@var{n} -fconstexpr-loop-limit=@var{n} @gol > --fno-elide-constructors @gol > +-fconstexpr-loop-nest-limit=@var{n} -fno-elide-constructors @gol > -fno-enforce-eh-specs @gol > -fno-gnu-keywords @gol > -fno-implicit-templates @gol > @@ -2522,10 +2522,19 @@ is 512. > > @item -fconstexpr-loop-limit=@var{n} > @opindex fconstexpr-loop-limit > -Set the maximum number of iterations for a loop in C++14 constexpr functions > -to @var{n}. A limit is needed to detect infinite loops during > +Set the maximum number of iterations for a single loop in C++14 constexpr > +functions to @var{n}. A limit is needed to detect infinite loops during > constant expression evaluation. The default is 262144 (1<<18). > > +@item -fconstexpr-loop-nest-limit=@var{n} > +@opindex fconstexpr-loop-nest-limit > +Set the maximum number of iterations for all loops in a loop nest in C++14 > +constexpr functions to @var{n}. Even when number of iterations of a single > +loop is limited with the above limit, if there are several nested loops and > +each of them has many iterations but still smaller than the above limit, > +the resulting evaluation of the loop nest might take too long. > +The default is 1048576 (1<<20). > + > @item -fdeduce-init-list > @opindex fdeduce-init-list > Enable deduction of a template type parameter as > --- gcc/c-family/c.opt.jj 2019-02-25 23:56:58.149055806 +0100 > +++ gcc/c-family/c.opt 2019-03-07 14:25:07.782639790 +0100 > @@ -1414,7 +1414,11 @@ C++ ObjC++ Joined RejectNegative UIntege > > fconstexpr-loop-limit= > C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) > Init(262144) > --fconstexpr-loop-limit=<number> Specify maximum constexpr loop > iteration count. > +-fconstexpr-loop-limit=<number> Specify maximum constexpr loop > iteration count of a single loop. > + > +fconstexpr-loop-nest-limit= > +C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_nest_limit) > Init(1048576) > +-fconstexpr-loop-nest-limit=<number> Specify maximum constexpr loop > iteration count for all nested loops. > > fdebug-cpp > C ObjC C++ ObjC++ > --- gcc/cp/constexpr.c.jj 2019-03-06 19:45:40.360751756 +0100 > +++ gcc/cp/constexpr.c 2019-03-07 14:03:00.040329107 +0100 > @@ -4190,8 +4190,20 @@ cxx_eval_loop_expr (const constexpr_ctx > default: > gcc_unreachable (); > } > + > + /* True on entry to cxx_eval_loop_expr if called indirectly from another > + cxx_eval_loop_expr. */ > + static bool constexpr_loop_nested; > + > + /* Number of evaluated loop iterations in the whole current loop nest. */ > + static int constexpr_loop_nest_count; > + > + bool save_constexpr_loop_nested = constexpr_loop_nested; > + constexpr_loop_nested = true; > + > hash_set<tree> save_exprs; > new_ctx.save_exprs = &save_exprs; > + > do > { > if (count != -1) > @@ -4248,6 +4260,24 @@ cxx_eval_loop_expr (const constexpr_ctx > *non_constant_p = true; > break; > } > + > + /* In nested loops, don't count the first iteration, as it has been > + counted in the parent loop already. */ > + if (count > (save_constexpr_loop_nested ? 1 : 0)) > + { > + if (++constexpr_loop_nest_count >= constexpr_loop_nest_limit) > + { > + if (!ctx->quiet) > + error_at (cp_expr_loc_or_loc (t, input_location), > + "%<constexpr%> loop iteration count in all nested " > + "loops exceeds limit of %d (use " > + "-fconstexpr-loop-nest-limit= to increase the > limit)", > + constexpr_loop_nest_limit); > + constexpr_loop_nest_count = 0; > + *non_constant_p = true; > + break; > + } > + } > } > while (!returns (jump_target) > && !breaks (jump_target) > @@ -4260,6 +4290,12 @@ cxx_eval_loop_expr (const constexpr_ctx > iter != save_exprs.end(); ++iter) > new_ctx.values->remove (*iter); > > + if (!save_constexpr_loop_nested) > + { > + constexpr_loop_nested = false; > + constexpr_loop_nest_count = 0; > + } > + > return NULL_TREE; > } > > --- gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C.jj 2019-03-07 > 14:28:45.664080874 +0100 > +++ gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C 2019-03-07 > 14:36:05.622894508 +0100 > @@ -0,0 +1,16 @@ > +// PR c++/87481 > +// { dg-do compile { target c++14 } } > +// { dg-options "-fconstexpr-loop-limit=98304 > -fconstexpr-loop-nest-limit=131072" } */ > + > +constexpr unsigned > +foo () > +{ > + unsigned int r = 0; > + for (int i = 0; i < 65536; i++) > + for (int j = 0; j < 65536; j++) > + for (int k = 0; k < 65536; k++) // { dg-error "'constexpr' loop > iteration count in all nested loops exceeds limit of 131072" } > + r += (i + j + k); > + return r; > +} > + > +constexpr auto x = foo (); // { dg-message "in 'constexpr' > expansion of" } > > Jakub