On Fri, Mar 08, 2019 at 02:51:42PM +0100, Richard Biener wrote:
> Well, I think having only a single limit is desirable which means we have to
> count something resembling the overall work done.  We don't have to document
> that it matches "statements" (whatever that exactly would be).
> 
> I don't see multi-megabyte constexpr arrays as an issue - do you think we'd
> reject them already when parsing them?  We could always decide to elide
> counting things we didn't do any real work on (like a literal '1' 
> initializer).

Ok, here is an updated patch that counts cxx_eval_constant_expression calls
when:
1) not in stmt skipping mode
2) not CONSTANT_CLASS_P
3) not location_wrapper_p
so that if there are huge constexpr array initializers that just contain
constants, they aren't counted towards the limit if there are just constants
wrapped in location wrappers.

The default limit is chosen such that on the new testcase it bails out after
about 15 seconds of computation on a fast machine (for a single
cxx_eval_outermost_constant_expression).  Wanted to find something so that
it doesn't trigger too often.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-03-15  Jakub Jelinek  <ja...@redhat.com>

        PR c++/87481
        * doc/invoke.texi (-fconstexpr-ops-limit=): Document.

        * c.opt (-fconstexpr-ops-limit=): New option.

        * constexpr.c (constexpr_ops_count): New variable.
        (cxx_eval_constant_expression): When not skipping, not constant class
        or location wrapper, increment constexpr_ops_count and if it is above
        constexpr_loop_nest_limit, diagnose failure.
        (cxx_eval_outermost_constant_expr): Clear constexpr_ops_count.

        * g++.dg/cpp1y/constexpr-87481.C: New test.

--- gcc/doc/invoke.texi.jj      2019-03-14 23:44:26.121588028 +0100
+++ gcc/doc/invoke.texi 2019-03-15 19:24:37.428486959 +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-ops-limit=@var{n} -fno-elide-constructors @gol
 -fno-enforce-eh-specs @gol
 -fno-gnu-keywords @gol
 -fno-implicit-templates @gol
@@ -2525,6 +2525,16 @@ Set the maximum number of iterations for
 to @var{n}.  A limit is needed to detect infinite loops during
 constant expression evaluation.  The default is 262144 (1<<18).
 
+@item -fconstexpr-ops-limit=@var{n}
+@opindex fconstexpr-ops-limit
+Set the maximum number of operations during a single constexpr evaluation.
+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, or if in a body of some loop or even outside
+of a loop too many expressions need to be evaluated, the resulting constexpr
+evaluation might take too long.
+The default is 33554432 (1<<25).
+
 @item -fdeduce-init-list
 @opindex fdeduce-init-list
 Enable deduction of a template type parameter as
--- gcc/c-family/c.opt.jj       2019-03-07 20:07:14.890098884 +0100
+++ gcc/c-family/c.opt  2019-03-15 19:22:06.298922976 +0100
@@ -1416,6 +1416,10 @@ 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-ops-limit=
+C++ ObjC++ Joined RejectNegative Host_Wide_Int Var(constexpr_ops_limit) 
Init(33554432)
+-fconstexpr-ops-limit=<number> Specify maximum number of constexpr operations 
during a single constexpr evaluation.
+
 fdebug-cpp
 C ObjC C++ ObjC++
 Emit debug annotations during preprocessing.
--- gcc/cp/constexpr.c.jj       2019-03-14 09:12:31.667710331 +0100
+++ gcc/cp/constexpr.c  2019-03-15 19:18:29.559416561 +0100
@@ -4335,6 +4335,11 @@ lookup_placeholder (const constexpr_ctx
   return ob;
 }
 
+/* Number of cxx_eval_constant_expression calls (except skipped ones,
+   on simple constants or location wrappers) encountered during current
+   cxx_eval_outermost_constant_expr call.  */
+static HOST_WIDE_INT constexpr_ops_count;
+
 /* Attempt to reduce the expression T to a constant value.
    On failure, issue diagnostic and return error_mark_node.  */
 /* FIXME unify with c_fully_fold */
@@ -4402,6 +4407,20 @@ cxx_eval_constant_expression (const cons
       return t;
     }
 
+  /* Avoid excessively long constexpr evaluations.  */
+  if (!location_wrapper_p (t)
+      && ++constexpr_ops_count >= constexpr_ops_limit)
+    {
+      if (!ctx->quiet)
+       error_at (cp_expr_loc_or_loc (t, input_location),
+                 "%<constexpr%> evaluation operation count exceeds limit of "
+                 "%wd (use -fconstexpr-ops-limit= to increase the limit)",
+                 constexpr_ops_limit);
+      constexpr_ops_count = INTTYPE_MINIMUM (HOST_WIDE_INT);
+      *non_constant_p = true;
+      return t;
+    }
+
   tree_code tcode = TREE_CODE (t);
   switch (tcode)
     {
@@ -5278,6 +5297,7 @@ cxx_eval_outermost_constant_expr (tree t
     }
 
   instantiate_constexpr_fns (r);
+  constexpr_ops_count = 0;
   r = cxx_eval_constant_expression (&ctx, r,
                                    false, &non_constant_p, &overflow_p);
 
--- gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C.jj     2019-03-15 
19:08:21.207253626 +0100
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C        2019-03-15 
19:26:10.895980368 +0100
@@ -0,0 +1,16 @@
+// PR c++/87481
+// { dg-do compile { target c++14 } }
+// { dg-options "-fconstexpr-loop-limit=98304 -fconstexpr-ops-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' evaluation 
operation count exceeds limit of 131072" "" { target *-*-* } 0 }
+       r += (i + j + k);
+  return r;
+}
+
+constexpr auto x = foo ();             // { dg-message "in 'constexpr' 
expansion of" }


        Jakub

Reply via email to