Re: [C++ PATCH] Reject out of bounds constexpr stores (PR c++/77830)

2016-12-21 Thread Jason Merrill

OK.


[C++ PATCH] Reject out of bounds constexpr stores (PR c++/77830)

2016-12-14 Thread Jakub Jelinek
Hi!

On the following testcase we ICE, because we don't diagnose invalid out of
bounds stores and create garbage CONSTRUCTOR that the middle-end ICEs on.
The following patch enables out of bounds diagnostics even for the case when
lval is true, but because lval = true is used not just for the lhs
of stores, but also e.g. for ADDR_EXPR handling, for lval = true it allows
also ARRAY_REF one past the last element.  And then in
cxx_eval_store_expression it detects the case of exactly one past the last
element and because we are dereferencing it (storing into it), diagnose
that.

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

2016-12-14  Jakub Jelinek  

PR c++/77830
* constexpr.c (cxx_eval_array_reference): Perform out of bounds
verification even if lval is true, just allow one past the last
element in that case.
(cxx_eval_store_expression): Detect stores to out of bound
ARRAY_REF.

* g++.dg/cpp1y/pr77830.C: New test.
* g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics.

--- gcc/cp/constexpr.c.jj   2016-12-08 23:17:58.0 +0100
+++ gcc/cp/constexpr.c  2016-12-14 16:38:54.494658094 +0100
@@ -2183,9 +2183,9 @@ cxx_eval_array_reference (const constexp
   lval,
   non_constant_p, overflow_p);
   tree index, oldidx;
-  HOST_WIDE_INT i;
-  tree elem_type;
-  unsigned len, elem_nchars = 1;
+  HOST_WIDE_INT i = 0;
+  tree elem_type = NULL_TREE;
+  unsigned len = 0, elem_nchars = 1;
   if (*non_constant_p)
 return t;
   oldidx = TREE_OPERAND (t, 1);
@@ -2193,39 +2193,38 @@ cxx_eval_array_reference (const constexp
false,
non_constant_p, overflow_p);
   VERIFY_CONSTANT (index);
-  if (lval && ary == oldary && index == oldidx)
-return t;
-  else if (lval)
-return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
-  elem_type = TREE_TYPE (TREE_TYPE (ary));
-  if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
-  && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
-  && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0
-ary = TREE_OPERAND (ary, 0);
-  if (TREE_CODE (ary) == CONSTRUCTOR)
-len = CONSTRUCTOR_NELTS (ary);
-  else if (TREE_CODE (ary) == STRING_CST)
+  if (!lval)
 {
-  elem_nchars = (TYPE_PRECISION (elem_type)
-/ TYPE_PRECISION (char_type_node));
-  len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
-}
-  else if (TREE_CODE (ary) == VECTOR_CST)
-len = VECTOR_CST_NELTS (ary);
-  else
-{
-  /* We can't do anything with other tree codes, so use
-VERIFY_CONSTANT to complain and fail.  */
-  VERIFY_CONSTANT (ary);
-  gcc_unreachable ();
-}
+  elem_type = TREE_TYPE (TREE_TYPE (ary));
+  if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
+ && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
+ && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0
+   ary = TREE_OPERAND (ary, 0);
+  if (TREE_CODE (ary) == CONSTRUCTOR)
+   len = CONSTRUCTOR_NELTS (ary);
+  else if (TREE_CODE (ary) == STRING_CST)
+   {
+ elem_nchars = (TYPE_PRECISION (elem_type)
+/ TYPE_PRECISION (char_type_node));
+ len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
+   }
+  else if (TREE_CODE (ary) == VECTOR_CST)
+   len = VECTOR_CST_NELTS (ary);
+  else
+   {
+ /* We can't do anything with other tree codes, so use
+VERIFY_CONSTANT to complain and fail.  */
+ VERIFY_CONSTANT (ary);
+ gcc_unreachable ();
+   }
 
-  if (!tree_fits_shwi_p (index)
-  || (i = tree_to_shwi (index)) < 0)
-{
-  diag_array_subscript (ctx, ary, index);
-  *non_constant_p = true;
-  return t;
+  if (!tree_fits_shwi_p (index)
+ || (i = tree_to_shwi (index)) < 0)
+   {
+ diag_array_subscript (ctx, ary, index);
+ *non_constant_p = true;
+ return t;
+   }
 }
 
   tree nelts;
@@ -2240,13 +2239,20 @@ cxx_eval_array_reference (const constexp
   nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
overflow_p);
   VERIFY_CONSTANT (nelts);
-  if (!tree_int_cst_lt (index, nelts))
+  if (lval
+  ? !tree_int_cst_le (index, nelts)
+  : !tree_int_cst_lt (index, nelts))
 {
   diag_array_subscript (ctx, ary, index);
   *non_constant_p = true;
   return t;
 }
 
+  if (lval && ary == oldary && index == oldidx)
+return t;
+  else if (lval)
+return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
+
   bool found;
   if (TREE_CODE (ary) == CONSTRUCTOR)
 {
@@ -3281,6 +3287,47 @@ cxx_eval_store_expression (const constex
   if (*non_constant_p)
 return t;
 
+  /* cxx_eval_array_reference for lval = true allows