PR sanitizer/79993 - ICE with VLA initialization from string
authorJason Merrill <jason@redhat.com>
Mon, 3 Apr 2017 21:15:36 +0000 (17:15 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 3 Apr 2017 21:15:36 +0000 (17:15 -0400)
PR c++/69487 - wrong VLA initialization from string
* init.c (finish_length_check): Split out from build_vec_init.
(build_vec_init): Handle STRING_CST.
* typeck2.c (split_nonconstant_init): Handle STRING_CST.
(digest_init_r): Don't give a STRING_CST VLA type.

From-SVN: r246662

gcc/cp/ChangeLog
gcc/cp/init.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/asan/pr78201.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/vla17.C [new file with mode: 0644]

index 743847908d0c431759d1a07871ea898e58f1aeef..f3c668b870de1d7af9cbf16f169323620dc1b74c 100644 (file)
@@ -1,3 +1,12 @@
+2017-04-03  Jason Merrill  <jason@redhat.com>
+
+       PR sanitizer/79993 - ICE with VLA initialization from string
+       PR c++/69487 - wrong VLA initialization from string
+       * init.c (finish_length_check): Split out from build_vec_init.
+       (build_vec_init): Handle STRING_CST.
+       * typeck2.c (split_nonconstant_init): Handle STRING_CST.
+       (digest_init_r): Don't give a STRING_CST VLA type.
+
 2017-03-31  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/79572
index 773279504eeb8cbcde2788f70d40c28bb4bc3114..2015205efd66ff01871076a84318c2da57652b16 100644 (file)
@@ -3884,6 +3884,35 @@ vec_copy_assign_is_trivial (tree inner_elt_type, tree init)
   return is_trivially_xible (MODIFY_EXPR, inner_elt_type, fromtype);
 }
 
+/* Subroutine of build_vec_init: Check that the array has at least N
+   elements.  Other parameters are local variables in build_vec_init.  */
+
+void
+finish_length_check (tree atype, tree iterator, tree obase, unsigned n)
+{
+  tree nelts = build_int_cst (ptrdiff_type_node, n - 1);
+  if (TREE_CODE (atype) != ARRAY_TYPE)
+    {
+      if (flag_exceptions)
+       {
+         tree c = fold_build2 (LT_EXPR, boolean_type_node, iterator,
+                               nelts);
+         c = build3 (COND_EXPR, void_type_node, c,
+                     throw_bad_array_new_length (), void_node);
+         finish_expr_stmt (c);
+       }
+      /* Don't check an array new when -fno-exceptions.  */
+    }
+  else if (flag_sanitize & SANITIZE_BOUNDS
+          && do_ubsan_in_current_function ())
+    {
+      /* Make sure the last element of the initializer is in bounds. */
+      finish_expr_stmt
+       (ubsan_instrument_bounds
+        (input_location, obase, &nelts, /*ignore_off_by_one*/false));
+    }
+}
+
 /* `build_vec_init' returns tree structure that performs
    initialization of a vector of aggregate types.
 
@@ -3932,6 +3961,8 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree obase = base;
   bool xvalue = false;
   bool errors = false;
+  location_t loc = (init ? EXPR_LOC_OR_LOC (init, input_location)
+                   : location_of (base));
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
     maxindex = array_type_nelts (atype);
@@ -3963,10 +3994,12 @@ build_vec_init (tree base, tree maxindex, tree init,
        }
     }
 
-  /* If we have a braced-init-list, make sure that the array
+  /* If we have a braced-init-list or string constant, make sure that the array
      is big enough for all the initializers.  */
-  bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR
-                      && CONSTRUCTOR_NELTS (init) > 0
+  bool length_check = (init
+                      && (TREE_CODE (init) == STRING_CST
+                          || (TREE_CODE (init) == CONSTRUCTOR
+                              && CONSTRUCTOR_NELTS (init) > 0))
                       && !TREE_CONSTANT (maxindex));
 
   if (init
@@ -4105,30 +4138,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       from_array = 0;
 
       if (length_check)
-       {
-         tree nelts = build_int_cst (ptrdiff_type_node,
-                                     CONSTRUCTOR_NELTS (init) - 1);
-         if (TREE_CODE (atype) != ARRAY_TYPE)
-           {
-             if (flag_exceptions)
-               {
-                 tree c = fold_build2 (LT_EXPR, boolean_type_node, iterator,
-                                       nelts);
-                 c = build3 (COND_EXPR, void_type_node, c,
-                             throw_bad_array_new_length (), void_node);
-                 finish_expr_stmt (c);
-               }
-             /* Don't check an array new when -fno-exceptions.  */
-           }
-         else if (flag_sanitize & SANITIZE_BOUNDS
-                  && do_ubsan_in_current_function ())
-           {
-             /* Make sure the last element of the initializer is in bounds. */
-             finish_expr_stmt
-               (ubsan_instrument_bounds
-                (input_location, obase, &nelts, /*ignore_off_by_one*/false));
-           }
-       }
+       finish_length_check (atype, iterator, obase, CONSTRUCTOR_NELTS (init));
 
       if (try_const)
        vec_alloc (const_vec, CONSTRUCTOR_NELTS (init));
@@ -4196,6 +4206,34 @@ build_vec_init (tree base, tree maxindex, tree init,
       /* Any elements without explicit initializers get T{}.  */
       empty_list = true;
     }
+  else if (init && TREE_CODE (init) == STRING_CST)
+    {
+      /* Check that the array is at least as long as the string.  */
+      if (length_check)
+       finish_length_check (atype, iterator, obase,
+                            TREE_STRING_LENGTH (init));
+      tree length = build_int_cst (ptrdiff_type_node,
+                                  TREE_STRING_LENGTH (init));
+
+      /* Copy the string to the first part of the array.  */
+      tree alias_set = build_int_cst (build_pointer_type (type), 0);
+      tree lhs = build2 (MEM_REF, TREE_TYPE (init), base, alias_set);
+      tree stmt = build2 (MODIFY_EXPR, void_type_node, lhs, init);
+      finish_expr_stmt (stmt);
+
+      /* Adjust the counter and pointer.  */
+      stmt = cp_build_binary_op (loc, MINUS_EXPR, iterator, length, complain);
+      stmt = build2 (MODIFY_EXPR, void_type_node, iterator, stmt);
+      finish_expr_stmt (stmt);
+
+      stmt = cp_build_binary_op (loc, PLUS_EXPR, base, length, complain);
+      stmt = build2 (MODIFY_EXPR, void_type_node, base, stmt);
+      finish_expr_stmt (stmt);
+
+      /* And set the rest of the array to NUL.  */
+      from_array = 0;
+      explicit_value_init_p = true;
+    }
   else if (from_array)
     {
       if (init)
index 58a01c98f2a5f9fb8797f8086007b92ca7a63ec6..d1a393059a49bb12a3cdac0994e62258bac2001d 100644 (file)
@@ -749,6 +749,10 @@ split_nonconstant_init (tree dest, tree init)
       DECL_INITIAL (dest) = init;
       TREE_READONLY (dest) = 0;
     }
+  else if (TREE_CODE (init) == STRING_CST
+          && array_of_runtime_bound_p (TREE_TYPE (dest)))
+    code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false,
+                          /*from array*/1, tf_warning_or_error);
   else
     code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
 
@@ -1066,7 +1070,8 @@ digest_init_r (tree type, tree init, bool nested, int flags,
                }
            }
 
-         if (type != TREE_TYPE (init))
+         if (type != TREE_TYPE (init)
+             && !variably_modified_type_p (type, NULL_TREE))
            {
              init = copy_node (init);
              TREE_TYPE (init) = type;
diff --git a/gcc/testsuite/g++.dg/asan/pr78201.C b/gcc/testsuite/g++.dg/asan/pr78201.C
new file mode 100644 (file)
index 0000000..931ef44
--- /dev/null
@@ -0,0 +1,13 @@
+// PR middle-end/78201
+// { dg-do compile }
+// { dg-options "-O2 -fsanitize=address" }
+
+struct B { long d (); } *c;
+long e;
+
+void
+foo ()
+{
+  char a[e] = "";
+  c && c->d();
+}
diff --git a/gcc/testsuite/g++.dg/ext/vla17.C b/gcc/testsuite/g++.dg/ext/vla17.C
new file mode 100644 (file)
index 0000000..431167c
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/69487
+// { dg-do run }
+// { dg-options -Wno-vla }
+
+int size = 6;
+
+int main()
+{
+  char buffer[size] = "";
+  for (int i = 0; i != size; ++i)
+    {
+      if (buffer[i] != 0)
+       __builtin_abort();
+    }
+}