PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
authorMartin Sebor <msebor@redhat.com>
Wed, 13 Apr 2016 23:26:41 +0000 (23:26 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Wed, 13 Apr 2016 23:26:41 +0000 (17:26 -0600)
PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected
PR c++/70588 - SIGBUS on a VLA larger than SIZE_MAX / 2

gcc/testsuite/ChangeLog:
2016-04-13  Martin Sebor  <msebor@redhat.com>

        PR c++/69517
        PR c++/70019
        PR c++/70588
        * c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
        * g++.dg/cpp1y/vla11.C: New test.
        * g++.dg/cpp1y/vla12.C: New test.
        * g++.dg/cpp1y/vla13.C: New test.
        * g++.dg/cpp1y/vla14.C: New test.
        * g++.dg/cpp1y/vla3.C: Restore deleted test.
        * gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer.
        * g++.dg/ubsan/vla-1.C: Disable exceptions.

gcc/cp/ChangeLog:
2016-04-13  Martin Sebor  <msebor@redhat.com>

        PR c++/69517
        PR c++/70019
        PR c++/70588
        * cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
        functions.
        * decl.c (check_initializer, cp_finish_decl): Call them.
        (reshape_init_r): Reject incompletely braced intializer-lists
        for VLAs.
        * init.c (throw_bad_array_length, build_vla_check)
        (build_vla_size_check, build_vla_init_check): Define new functions.
        * typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
        to detect a VLA.
        (store_init_value): Same.

gcc/doc/ChangeLog:
2016-04-13  Martin Sebor  <msebor@redhat.com>

        PR c++/69517
        PR c++/70019
        PR c++/70588
        * extend.texi (Variable Length): Document C++ specifics.

libstdc++-v3/ChangeLog:
2016-04-13  Martin Sebor  <msebor@redhat.com>

        PR c++/69517
        * testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
       upper bound is positive.

From-SVN: r234966

18 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/typeck2.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/ubsan/vla-1.c
gcc/testsuite/g++.dg/cpp1y/vla11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/vla12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/vla13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/vla14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/vla3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/array24.C
gcc/testsuite/g++.dg/ubsan/vla-1.C
libstdc++-v3/ChangeLog
libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc

index 26db5fefac7058254d928bf4d4364b6f5e0250de..a3c6c12c3883dc8a3292f57b454170b85ac34edc 100644 (file)
@@ -1,3 +1,10 @@
+2016-04-13  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69517
+       PR c++/70019
+       PR c++/70588
+       * doc/extend.texi (Variable Length): Document C++ specifics.
+
 2016-04-13  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/70641
index c9929b63b9c380d419cd05441dbca2ce806e81e1..866b4f2dbba3fbe65ee59f31b1fd58d82cfe539b 100644 (file)
@@ -1,3 +1,19 @@
+2016-04-13  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69517
+       PR c++/70019
+       PR c++/70588
+       * cp-tree.h (throw_bad_array_length, build_vla_check): Declare new
+       functions.
+       * decl.c (check_initializer, cp_finish_decl): Call them.
+       (reshape_init_r): Reject incompletely braced intializer-lists
+       for VLAs.
+       * init.c (throw_bad_array_length, build_vla_check)
+       (build_vla_size_check, build_vla_init_check): Define new functions.
+       * typeck2.c (split_nonconstant_init_1): Use variably_modified_type_p()
+       to detect a VLA.
+       (store_init_value): Same.
+
 2016-04-13  Jason Merrill  <jason@redhat.com>
 
        Warn about empty parameter ABI with -Wabi=9.
index 8d721c75849b96c7e26ad582553d5f14fa890660..87e3ea0b2ee63ed44656c70312dc5161e6bbdb17 100644 (file)
@@ -5950,6 +5950,7 @@ extern tree build_value_init_noctor               (tree, tsubst_flags_t);
 extern tree get_nsdmi                          (tree, bool);
 extern tree build_offset_ref                   (tree, tree, bool,
                                                 tsubst_flags_t);
+extern tree throw_bad_array_length              (void);
 extern tree throw_bad_array_new_length         (void);
 extern tree build_new                          (vec<tree, va_gc> **, tree, tree,
                                                 vec<tree, va_gc> **, int,
@@ -5971,6 +5972,7 @@ extern tree scalar_constant_value         (tree);
 extern tree decl_really_constant_value         (tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
 extern tree build_vtbl_address                  (tree);
+extern tree build_vla_check                     (tree, tree = NULL_TREE);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl         (tree);
index 7099199dea32f0d89c497d3e5ff88329ba634ecf..42e853f21908a19eaaef7b4b722ba30171efe735 100644 (file)
@@ -5896,6 +5896,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
            }
        }
 
+      if (variably_modified_type_p (type, NULL_TREE))
+       {
+         /* Require VLAs to have their initializers fully braced
+            to avoid initializing the wrong elements.  */
+         if (complain & tf_error)
+           error ("missing braces around initializer for a variable length "
+                  "array %qT", type);
+         return error_mark_node;
+       }
+
       warning (OPT_Wmissing_braces, "missing braces around initializer for %qT",
               type);
     }
@@ -6048,6 +6058,10 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
     /* There is no way to make a variable-sized class type in GNU C++.  */
     gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
 
+  /* Initializer exression used to check invalid VLA bounds and excess
+     initializer elements.  */
+  tree saved_init_for_vla_check = NULL_TREE;
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
     {
       int init_len = vec_safe_length (CONSTRUCTOR_ELTS (init));
@@ -6199,7 +6213,9 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
              && PAREN_STRING_LITERAL_P (DECL_INITIAL (decl)))
            warning (0, "array %qD initialized by parenthesized string literal %qE",
                     decl, DECL_INITIAL (decl));
-         init = NULL;
+
+         saved_init_for_vla_check = init;
+         init = NULL_TREE;
        }
     }
   else
@@ -6213,6 +6229,33 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       check_for_uninitialized_const_var (decl);
     }
 
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && variably_modified_type_p (type, NULL_TREE)
+      && !processing_template_decl)
+    {
+      /* Statically check for overflow in VLA bounds and build
+        an expression that checks at runtime whether the VLA
+        is erroneous due to invalid (runtime) bounds.
+        Another expression to check for excess initializers
+        is built in build_vec_init.  */
+      tree check = build_vla_check (TREE_TYPE (decl), saved_init_for_vla_check);
+
+      if (flag_exceptions && current_function_decl
+         /* Avoid instrumenting constexpr functions for now.
+            Those must be checked statically, and the (non-
+            constexpr) dynamic instrumentation would cause
+            them to be rejected.  See c++/70507.  */
+         && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+       {
+         /* Use the runtime check only when exceptions are enabled.
+            Otherwise let bad things happen...  */
+         check = build3 (COND_EXPR, void_type_node, check,
+                         throw_bad_array_length (), void_node);
+
+         finish_expr_stmt (check);
+       }
+    }
+
   if (init && init != error_mark_node)
     init_code = build2 (INIT_EXPR, type, decl, init);
 
index 5997d53ddb5503dd727c09f52026289f4b7f3772..ec19d72630206018174d39d8ecd7b4fd5d22d2c1 100644 (file)
@@ -2262,6 +2262,20 @@ diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool compla
   return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
 }
 
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+   in the bounds of a variable length array overflowed.  */
+
+tree
+throw_bad_array_length (void)
+{
+  tree fn = get_identifier ("__cxa_throw_bad_array_length");
+  if (!get_global_value_if_present (fn, &fn))
+    fn = push_throw_library_fn (fn, build_function_type_list (void_type_node,
+                                                             NULL_TREE));
+
+  return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
+}
+
 /* Call __cxa_bad_array_new_length to indicate that the size calculation
    overflowed.  Pretend it returns sizetype so that it plays nicely in the
    COND_EXPR.  */
@@ -4709,3 +4723,304 @@ build_vec_delete (tree base, tree maxindex,
 
   return rval;
 }
+
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA TYPE is erroneous due
+   either to its bounds being invalid or to integer overflow in
+   the computation of its total size.
+   CHECK is the boolean expression being built, initialized to
+   boolean_false_node.
+   VLASIZE is used internally to pass the incrementally computed
+   size of the VLA object down to its recursive invocations.
+   MAX_VLASIZE is the maximum valid size of the VLA in bytes.
+   CST_SIZE is the product of the VLA's constant dimensions.  */
+
+static tree
+build_vla_size_check (tree check,
+                     tree type,
+                     tree vlasize,
+                     tree max_vlasize,
+                     offset_int *cst_size)
+{
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  tree vlasizeaddr = build_unary_op (input_location, ADDR_EXPR, vlasize, 0);
+
+  bool overflow = false;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type.  */
+      tree inner_nelts = array_type_nelts_top (type);
+      tree inner_nelts_cst = maybe_constant_value (inner_nelts);
+
+      if (TREE_CODE (inner_nelts_cst) == INTEGER_CST)
+       {
+         /* The upper bound is a constant expression.  Compute the product
+            of the constant upper bounds seen so far so that overflow can
+            be diagnosed.  */
+         offset_int result = wi::mul (wi::to_offset (inner_nelts_cst),
+                                      *cst_size, SIGNED, &overflow);
+         *cst_size = overflow ? 0 : result;
+       }
+
+      /* Check for overflow in the VLAs (runtime) upper bounds.  */
+      tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+                                        vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                          check, vflowcheck);
+
+      /* Recursively check for overflow in the remaining major bounds.  */
+      check = build_vla_size_check (check, TREE_TYPE (type),
+                                   vlasize, max_vlasize,
+                                   cst_size);
+    }
+  else
+    {
+      /* Get the size of the VLA element type in bytes.  */
+      tree typesize = TYPE_SIZE_UNIT (type);
+
+      /* See if the size, when multipled by the product of the VLA's
+        constant dimensions, is within range of size_t.  If not,
+        the VLA is definitely erroneous amd must be diagnosed at
+        compile time.  */
+      offset_int result = wi::mul (wi::to_offset (typesize), *cst_size,
+                                  SIGNED, &overflow);
+      *cst_size = overflow ? 0 : result;
+
+      /* Multiply the (non-constant) VLA size so far by the element size,
+        checking for overflow, and replacing the value of vlasize with
+        the product in the absence of overflow.  This size is the total
+        runtime size of the VLA in bytes.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+                                        vlasize, vlasizeaddr);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                          check, vflowcheck);
+
+      /* Check to see if the final VLA size exceeds the maximum.  */
+      tree sizecheck = fold_build2 (LT_EXPR, boolean_type_node,
+                                   max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                          check, sizecheck);
+
+      /* Also check to see if the final array size is zero (the size
+        is unsigned so the earlier overflow check detects negative
+        values as well.  */
+      tree zerocheck = fold_build2 (EQ_EXPR, boolean_type_node,
+                                   vlasize, size_zero_node);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                          check, zerocheck);
+    }
+
+  /* Diagnose overflow determined at compile time.  */
+  if (overflow)
+    {
+      error ("integer overflow in variable array size");
+      /* Reset to suppress any further diagnostics.  */
+      *cst_size = 0;
+    }
+
+  return check;
+}
+
+/* The implementation of build_vla_check() that recursively builds
+   an expression to determine whether the VLA initializer-list for
+   TYPE is erroneous due to excess initializers.
+   CHECK is the boolean expression being built, initialized to
+   the result of build_vla_size_check().
+   INIT is the VLA initializer expression to check against TYPE.
+   On the first (non-recursive) call, INIT_ELTS is set either to 1,
+   or to the number of elements in the initializer-list for VLAs
+   of unspecified (major) bound.  On subsequent (recursive) calls.
+   it is set to NULL and computed from the number of elements in
+   the (nested) initializer-list.
+*/
+
+static tree
+build_vla_init_check (tree check, tree type, tree init, tree init_elts)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Compute the upper bound of this array type unless it has
+        already been computed by the caller for an array of unspecified
+        bound, as in 'T a[];'  */
+      tree inner_nelts = init_elts ? init_elts : array_type_nelts_top (type);
+
+      size_t len;
+
+      if (TREE_CODE (init) == CONSTRUCTOR)
+       {
+         /* The initializer of this array is itself an array.  Build
+            an expression to check if the number of elements in the
+            initializer array exceeds the upper bound of the type
+            of the object being initialized.  */
+         if (vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init))
+           {
+             len = v->length ();
+             tree initelts = build_int_cstu (size_type_node, len);
+             tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+                                           inner_nelts, initelts);
+
+             check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                                  check, initcheck);
+
+             constructor_elt *ce;
+             HOST_WIDE_INT i;
+
+             /* Iterate over all non-empty initializers in this array,
+                recursively building expressions to see if the elements
+                of each are in excess of the corresponding (runtime)
+                bound of the array type.  */
+             FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+               check = build_vla_init_check (check, TREE_TYPE (type),
+                                             ce->value, NULL_TREE);
+           }
+       }
+      else if (TREE_CODE (init) == STRING_CST
+              && (len = TREE_STRING_LENGTH (init)))
+       {
+         /* The initializer of this array is a string.  */
+         tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+         len /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+         /* A C++ string literal initializer must have at most as many
+            characters as there are elements in the array, including
+            the terminating NUL.  */
+         tree initelts = build_int_cstu (size_type_node, len);
+         tree initcheck = fold_build2 (LT_EXPR, boolean_type_node,
+                                       inner_nelts, initelts);
+         check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+                              check, initcheck);
+       }
+      else if (TREE_CODE (init) == ERROR_MARK)
+       {
+         // No checking is possible.
+         check = boolean_false_node;
+       }
+      else
+       {
+         /* What's this array initializer?  */
+         gcc_unreachable ();
+       }
+    }
+
+  return check;
+}
+
+/* Build an expression to determine whether the VLA TYPE is erroneous.
+   INIT is the VLA initializer expression or NULL_TREE when the VLA is
+   not initialized.  */
+
+tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+  tree check = boolean_false_node;
+
+  /* The product of all constant dimensions of the VLA, initialized
+     to either 1 in the common case or to the number of elements in
+     the VLA's initializer-list for VLAs of unspecified (major)
+     bound.  */
+  offset_int cst_size = 1;
+
+  /* The initial size of the VLA to start the computation of the total
+     size with.  Like CST_SIZE above, initialized to 1 or the number
+     of elements in the VLA's initializer-list for VLAs of unspecified
+     bound.  */
+  tree initial_size = size_one_node;
+
+  /* For a VLA of unspecified (major) bound, the number of elements
+     it is initialized with determined from the initializer-list.  */
+  tree initial_elts = NULL_TREE;
+
+  if (init)
+    {
+      /* Determine the upper bound of the VLA of unspecified bound,
+        as in 'T a[];' if this is such a VLA.  Such a VLA can be
+        initialized with any number of elements but the number of
+        elements so determined must be used to check the total size
+        of the VLA.  */
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
+
+      if (tree dom = TYPE_DOMAIN (type))
+       if (tree max = TYPE_MAX_VALUE (dom))
+         if (integer_zerop (max))
+           {
+             if (TREE_CODE (init) == CONSTRUCTOR)
+               {
+                 vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (init);
+
+                 /* Since the upper bound of every array must be positive
+                    a VLA with an unspecified major bound must be initized
+                    by a non-empty initializer list.  */
+                 gcc_assert (v != NULL);
+
+                 cst_size = v->length ();
+               }
+             else if (TREE_CODE (init) == STRING_CST)
+               {
+                 /* The initializer is a (possibly empty) string consisting
+                    at a minumum of one character, the terminating NUL.
+                    This condition implies a definition like
+                      char s [][N] = "";
+                    which is an error but even though it has been diagnosed
+                    by this point the initializer still winds up here.  */
+                 size_t nchars = TREE_STRING_LENGTH (init);
+                 tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+                 nchars /= TYPE_PRECISION (ctype) / BITS_PER_UNIT;
+
+                 cst_size = nchars + 1;
+               }
+
+             initial_elts = wide_int_to_tree (size_type_node, cst_size);
+             initial_size = initial_elts;
+           }
+    }
+
+  /* Build a variable storing the total runtime size of the VLA and
+     initialize it either to 1 (in the common case) or to the number
+     of topmost elements in the initializer-list when the VLA is
+     an array of unspecified (major) bound.  */
+  tree vlasize = build_decl (input_location,
+                            VAR_DECL, NULL_TREE, sizetype);
+  DECL_ARTIFICIAL (vlasize) = 1;
+  DECL_IGNORED_P (vlasize) = 1;
+  DECL_CONTEXT (vlasize) = current_function_decl;
+  DECL_INITIAL (vlasize) = initial_size;
+  vlasize = pushdecl (vlasize);
+  add_decl_expr (vlasize);
+
+  /* Impose a lenient limit on the size of the biggest VLA in bytes.
+     FIXME: Tighten up the limit to make it more useful and make it
+     configurable for users with unusual requirements.  */
+  tree max_vlasize
+    = fold_build2 (RSHIFT_EXPR, size_type_node,
+                  build_all_ones_cst (size_type_node),
+                  integer_one_node);
+
+  /* Build an expression that checks the runtime bounds of the VLA
+     for invalid values and the total size of the VLA for overflow.  */
+  check = build_vla_size_check (check, type, vlasize, max_vlasize, &cst_size);
+
+  if (wi::ltu_p (wi::to_offset (max_vlasize), cst_size))
+    {
+      /* Issue the warning only in the "topmost" (non-recursive) call
+        to avoid duplicating diagnostics.  This is only a warning to
+        allow programs to be portable to more permissive environments.  */
+      warning (OPT_Wvla, "size of variable length array exceeds maximum "
+              "of %qE bytes",  max_vlasize);
+    }
+
+  if (init)
+    {
+      /* Build an expression that checks the VLA initializer expression
+        against the type of the VLA for excess elements.  */
+      check = build_vla_init_check (check, type, init, initial_elts);
+    }
+
+  return check;
+}
index b921689808a174199d73bc4534c9725c1a290a0b..eba19ca11acbc943f11d88bd8e17de6e01e07750 100644 (file)
@@ -603,7 +603,7 @@ split_nonconstant_init_1 (tree dest, tree init)
       array_type_p = true;
       if ((TREE_SIDE_EFFECTS (init)
           && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-         || array_of_runtime_bound_p (type))
+         || variably_modified_type_p (type, NULL_TREE))
        {
          /* For an array, we only need/want a single cleanup region rather
             than one per element.  */
@@ -845,7 +845,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
      will perform the dynamic initialization.  */
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
-         || array_of_runtime_bound_p (type)
+         || variably_modified_type_p (type, NULL_TREE)
          || ! reduced_constant_expression_p (value)))
     return split_nonconstant_init (decl, value);
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL
index a5a8b23df275b70f047a3af9f79fa18a8542dcc0..6687d595d3cad9d2497367adee66b1a9fa963ce3 100644 (file)
@@ -1638,14 +1638,48 @@ foo (int n)
 You can use the function @code{alloca} to get an effect much like
 variable-length arrays.  The function @code{alloca} is available in
 many other C implementations (but not in all).  On the other hand,
-variable-length arrays are more elegant.
+variable-length arrays are available in GCC for all targets and
+provide type safety.
 
 There are other differences between these two methods.  Space allocated
 with @code{alloca} exists until the containing @emph{function} returns.
 The space for a variable-length array is deallocated as soon as the array
 name's scope ends, unless you also use @code{alloca} in this scope.
 
-You can also use variable-length arrays as arguments to functions:
+Unlike GCC, G++ instruments variable-length arrays (@xref{Variable Length})
+with checks for erroneous uses: when a variable-length array object is
+created its runtime bounds are checked to detect non-positive values,
+integer overflows, sizes in excess of SIZE_MAX / 2 bytes, and excess
+initializers.  When an erroneous variable-length array is detected
+the runtime arranges for an exception to be thrown that matches a handler
+of type @code{std::bad_array_length}.
+
+Also unlike GCC, G++ allows variable-length arrays to be initialized.
+However, unlike initializer lists for ordinary multidimensional arrays,
+those for multidimensional variable-length arrays must be enclosed in
+pairs of curly braces delimiting each sequence of values to use to
+initialize each subarray.  Initializer lists that aren't unambiguously
+enclosed in braces are rejected with an error.  For example, in the
+following function, the initializer list for the ordinary @code{array}
+is accepted even though it isn't fully enclosed in braces.  The same
+initializer list, however, wouldn't be accepted for a multidimensional
+variable-length array.  To initialize the variable-length array @code{vla},
+the elements of the subarray @code{vla[m]} must be enclosed in braces
+as shown.  As with ordinary arrays, elements that aren't initialized
+explicitly are default-initialized.
+
+@smallexample
+void
+foo (int m, int n)
+@{
+  int array[2][3] = @{ 1, 2, 4, 5, 6 @};
+  int vla[m][n] = @{ @{ 1, 2 @}, @{ 4, 5, 6 @} @};
+@}
+@end smallexample
+
+
+In C programs (but not in C++) variable-length arrays can also be declared
+as function arguments:
 
 @smallexample
 struct entry
index 5e047c60a9c8ad15dc41023cefb4d9d9c32fbe5e..b07b8b24dbd093065914d29c2e9016e34f1fafda 100644 (file)
@@ -1,3 +1,17 @@
+2016-04-13  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69517
+       PR c++/70019
+       PR c++/70588
+       * c-c++-common/ubsan/vla-1.c (main): Catch exceptions.
+       * g++.dg/cpp1y/vla11.C: New test.
+       * g++.dg/cpp1y/vla12.C: New test.
+       * g++.dg/cpp1y/vla13.C: New test.
+       * g++.dg/cpp1y/vla14.C: New test.
+       * g++.dg/cpp1y/vla3.C: Restore deleted test.
+       * gcc/testsuite/g++.dg/init/array24.C: Fully brace VLA initializer.
+       * g++.dg/ubsan/vla-1.C: Disable exceptions.
+
 2016-04-13  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/70641
index 52ade3aab7566dce3ca7ef931ac65895005d5e13..27ef110f52cf50b24de68f53eebb97430fd46548 100644 (file)
@@ -87,18 +87,24 @@ fn12 (void)
 int
 main (void)
 {
-  fn1 ();
-  fn2 ();
-  fn3 ();
-  fn4 ();
-  fn5 ();
-  fn6 ();
-  fn7 ();
-  fn8 ();
-  fn9 ();
-  fn10 ();
-  fn11 ();
-  fn12 ();
+#if __cplusplus
+#  define TRY(stmt)   do { try { stmt; } catch (...) { } } while (0)
+#else
+#  define TRY(stmt)   stmt
+#endif
+
+  TRY (fn1 ());
+  TRY (fn2 ());
+  TRY (fn3 ());
+  TRY (fn4 ());
+  TRY (fn5 ());
+  TRY (fn6 ());
+  TRY (fn7 ());
+  TRY (fn8 ());
+  TRY (fn9 ());
+  TRY (fn10 ());
+  TRY (fn11 ());
+  TRY (fn12 ());
   return 0;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla11.C b/gcc/testsuite/g++.dg/cpp1y/vla11.C
new file mode 100644 (file)
index 0000000..af9624a
--- /dev/null
@@ -0,0 +1,711 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// PR c++/70019 - VLA size overflow not detected
+//
+// Runtime test to verify that attempting to either construct a VLA with
+// erroneous bounds, or initialize one with an initializer-list that
+// contains more elements than the VLA's non-constant (runtime) bounds
+// causes an exception to be thrown.  Test also verifies that valid
+// VLAs and their initializers don't cause such an exception.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+#define UINT_MAX   (~0U)
+#define ULONG_MAX  (~0LU)
+
+#define INT_MIN    (-__INT_MAX__ - 1)
+#define LONG_MIN   (-__LONG_MAX__ - 1)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+                     "exception %sthrown as expected\n",
+                     line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Type to exercise VLA with.  TYPESIZE is the size of the type in bytes.
+// Using a template serves two purposes.  First, it makes it possible to
+// parameterize the test on VLAs of different size.  Second, it verifies
+// that the checking code can deal with templates (i.e., completes
+// the element type of the VLA when necessary).
+template <unsigned TypeSize>
+struct alignas (TypeSize) TestType
+{
+  char data;
+};
+
+// Test function invoked with a pointer to each test case.  Must
+// return a value though what value doesn't matter.
+int __attribute__ ((noclone, noinline))
+tester (int (*testcase)(const char*),
+       const char *str, int line, bool expect)
+{
+  try
+    {
+      return testcase (str);
+    }
+  catch (...)
+    {
+      return sink (0, line, expect, str);
+    }
+}
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(TypeSize, Dims, Init, Expect)                             \
+  static int CAT (testcase, __LINE__)(const char *str)                 \
+  {                                                                    \
+    TestType<TypeSize> vla Dims Init;                                  \
+    static_assert (sizeof (TestType<TypeSize>) == TypeSize,            \
+                  "wrong test type size");                             \
+    return sink (vla, __LINE__, Expect, str);                          \
+  }                                                                    \
+  const int CAT (dummy, __LINE__)                                      \
+    = tester (CAT (testcase, __LINE__),                                        \
+             "T<" #TypeSize "> a" #Dims " " STR (Init) ";",            \
+             __LINE__, Expect)
+
+
+// Create and run a test function exercising a VLA definition
+// of one of the following forms:
+//    TestType<Size> VLA Dims;        // uninitialized (with Init ())
+// or:
+//    TestType<Size> VLA Dims Init;   // initialized (with = Init ({...})
+//
+//    +-- Element Size (in Bytes)
+//    |  +-- VLA Dimensions (constant as in [3], otherwise d(3))
+//    |  |         +-- VLA Initializer Expression (if any)
+//    |  |         |                  +-- Expect Exception
+//    |  |         |                  |
+//    V  V         V                  V
+TEST (1, [d(0)],   Init (/* none*/),  true);   // uninitialized
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [d(0)],   Init ({}),         true);
+#endif
+TEST (1, [d(0)],   Init ({1}),        true);   // initialized with " {1}"
+TEST (1, [d(0)],   = Init ({1}),      true);   // initialized with "= {1}"
+
+TEST (1, [d(1)],   Init (),           false);
+TEST (1, [d(1)],   Init ({}),         false);
+TEST (1, [d(1)],   = Init ({}),       false);
+TEST (1, [d(1)],   Init ({1}),        false);
+TEST (1, [d(1)],   = Init ({1}),      false);
+TEST (1, [d(1)],   Init ({1, 2}),     true);
+TEST (1, [d(1)],   = Init ({1, 2}),   true);
+
+TEST (1, [d(2)],   Init (),           false);
+TEST (1, [d(2)],   Init ({}),         false);
+TEST (1, [d(2)],   Init ({1}),        false);
+TEST (1, [d(2)],   Init ({1, 2}),     false);
+TEST (1, [d(2)],   Init ({1, 2, 3}),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous one dimensional VLAs.
+TEST (1, [d(MAX)], Init (),           false);
+TEST (1, [d(MAX)], Init ({}),         false);
+TEST (1, [d(MAX)], Init ({1}),        false);
+TEST (1, [d(MAX)], Init ({1, 2}),     false);
+TEST (1, [d(MAX)], Init ({1, 2, 3}),  false);
+
+TEST ( 2, [d(MAX / 2)],   Init (),    false);
+TEST ( 4, [d(MAX / 4)],   Init (),    false);
+TEST ( 8, [d(MAX / 8)],   Init (),    false);
+TEST (16, [d(MAX / 16)],  Init (),    false);
+TEST (32, [d(MAX / 32)],  Init (),    false);
+TEST (64, [d(MAX / 64)],  Init (),    false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// One dimensional VLAs with a negative upper bound.
+TEST (1, [d(LONG_MIN)],  Init (),       true);
+TEST (1, [d(INT_MIN)],   Init (),       true);
+TEST (1, [d(-1234)],     Init (),       true);
+TEST (1, [d(-1)],        Init (),       true);
+
+// Excessively large one dimensional VLAs.
+TEST ( 1, [d(MAX + 1)],   Init (),      true);
+TEST ( 2, [d(MAX)],       Init (),      true);
+TEST ( 4, [d(MAX / 2)],   Init (),      true);
+TEST ( 4, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 2)],   Init (),      true);
+TEST ( 8, [d(MAX / 3)],   Init (),      true);
+TEST ( 8, [d(MAX / 4)],   Init (),      true);
+TEST ( 8, [d(MAX / 5)],   Init (),      true);
+TEST ( 8, [d(MAX / 6)],   Init (),      true);
+TEST ( 8, [d(MAX / 7)],   Init (),      true);
+TEST (16, [d(MAX / 15)],  Init (),      true);
+TEST (32, [d(MAX / 31)],  Init (),      true);
+TEST (64, [d(MAX / 63)],  Init (),      true);
+TEST ( 1, [d(SIZE_MAX)],  Init (),      true);
+
+TEST (1, [d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [d(INT_MIN)],   Init ({}),     true);
+TEST (1, [d(-1)],        Init ({}),     true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)],  Init ({0}),    true);
+TEST (1, [d(INT_MIN)],   Init ({0}),    true);
+TEST (1, [d(-1)],        Init ({0}),    true);
+
+TEST (1, [d(SIZE_MAX)],  Init ({0}),    true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init (), true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init (), true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)  + 1], Init ({1}),             true);
+TEST ( 2, [d(SIZE_MAX/4)  + 1], Init ({1, 2}),          true);
+TEST ( 4, [d(SIZE_MAX/8)  + 1], Init ({1, 2, 3}),       true);
+TEST ( 8, [d(SIZE_MAX/16) + 1], Init ({1, 2, 3, 4}),    true);
+TEST (16, [d(SIZE_MAX/32) + 1], Init ({1, 2, 3, 4, 5}), true);
+
+// Two dimensional VLAs with one constant bound.
+
+TEST (1, [1][d(0)],   Init (),          true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(0)],   Init ({}),        true);
+#endif
+TEST (1, [ ][d(0)],   Init ({{1}}),     true);   // unspecified bound
+TEST (1, [1][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [1][d(1)],   Init (),             false);
+TEST (1, [1][d(1)],   Init ({{1}}),        false);
+TEST (1, [1][d(1)],   Init ({{1, 2}}),     true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [1][d(2)],   Init (),             false);
+TEST (1, [1][d(2)],   Init ({{1}}),        false);
+TEST (1, [1][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [ ][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [1][d(2)],   Init ({{1, 2, 3}}),  true);
+TEST (1, [ ][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [2][d(1)],   Init (),                 false);
+TEST (1, [2][d(1)],   Init ({{1}}),            false);
+TEST (1, [ ][d(1)],   Init ({{1}}),            false);
+TEST (1, [2][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [ ][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [2][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [2][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [ ][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [2][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [2][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+TEST (1, [ ][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [2][d(2)],   Init (),                       false);
+TEST (1, [2][d(2)],   Init ({{1}}),                  false);
+TEST (1, [2][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [2][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [2][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [2][d(3)],   Init (),                          false);
+TEST (1, [2][d(3)],   Init ({{1}}),                     false);
+TEST (1, [2][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [2][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [2][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [2][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [1][d(MAX)], Init (),                 false);
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][d(MAX)], Init ({}),               false);
+#  endif
+TEST (1, [1][d(MAX)], Init ({{1}}),            false);
+TEST (1, [1][d(MAX)], Init ({{1, 2}}),         false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3}}),      false);
+TEST (1, [1][d(MAX)], Init ({{1, 2, 3, 4}}),   false);
+
+TEST (1, [2][d(MAX / 2)], Init (),                       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}}),                  false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}}),               false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}}),            false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3, 4}}),         false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2}}),             false);
+TEST (1, [2][d(MAX / 2)], Init ({{1}, {2, 3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3}}),          false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),       false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),    false);
+TEST (1, [2][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Excessively large two dimensional VLAs.
+TEST (1, [1][d(LONG_MIN)],  Init (),       true);
+TEST (1, [1][d(INT_MIN)],   Init (),       true);
+TEST (1, [1][d(-1)],        Init (),       true);
+
+TEST (1, [1][d(SIZE_MAX)],  Init (),       true);
+
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [1][d(LONG_MIN)],  Init ({}),     true);
+TEST (1, [1][d(INT_MIN)],   Init ({}),     true);
+TEST (1, [1][d(-1)],        Init ({}),     true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({}),     true);
+#endif
+
+TEST (1, [1][d(LONG_MIN)],  Init ({{0}}),  true);
+TEST (1, [1][d(INT_MIN)],   Init ({{0}}),  true);
+TEST (1, [1][d(-1)],        Init ({{0}}),  true);
+TEST (1, [1][d(SIZE_MAX)],  Init ({{0}}),  true);
+
+TEST (1, [d(LONG_MIN)][1],  Init (),       true);
+TEST (1, [d(INT_MIN)][1],   Init (),       true);
+TEST (1, [d(-1)][1],        Init (),       true);
+TEST (1, [d(SIZE_MAX)][1],  Init (),       true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({}),     true);
+TEST (1, [d(INT_MIN)][1],   Init ({}),     true);
+TEST (1, [d(-1)][1],        Init ({}),     true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({}),     true);
+
+TEST (1, [d(LONG_MIN)][1],  Init ({{0}}),  true);
+TEST (1, [d(INT_MIN)][1],   Init ({{0}}),  true);
+TEST (1, [d(-1)][1],        Init ({{0}}),  true);
+TEST (1, [d(SIZE_MAX)][1],  Init ({{0}}),  true);
+
+// Two dimensional VLAs with no constant bound.
+TEST (1, [d(0)][d(0)],   Init (),          true);
+TEST (1, [d(0)][d(0)],   Init ({}),        true);
+#if !BUG_58646
+// The following cause an ICE due to c++/58646.
+TEST (1, [d(0)][d(0)],   Init ({{}}),      true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {}}),  true);
+#endif
+
+TEST (1, [d(0)][d(0)],   Init ({{1}}),     true);
+TEST (1, [d(0)][d(0)],   Init ({{1, 2}}),  true);
+#if !BUG_58646
+TEST (1, [d(0)][d(0)],   Init ({{1}, {}}), true);
+TEST (1, [d(0)][d(0)],   Init ({{}, {1}}), true);
+#endif
+
+TEST (1, [d(1)][d(0)],   Init (),          true);
+TEST (1, [d(1)][d(0)],   Init ({}),        true);
+TEST (1, [d(1)][d(0)],   Init ({{1}}),     true);
+
+TEST (1, [d(1)][d(1)],   Init (),             false);
+TEST (1, [d(1)][d(1)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(1)],   Init ({{1, 2}}),     true);
+
+TEST (1, [d(1)][d(2)],   Init (),             false);
+TEST (1, [d(1)][d(2)],   Init ({{1}}),        false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2}}),     false);
+TEST (1, [d(1)][d(2)],   Init ({{1, 2, 3}}),  true);
+
+TEST (1, [d(2)][d(1)],   Init (),                 false);
+TEST (1, [d(2)][d(1)],   Init ({{1}}),            false);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2}}),       false);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}}),         true);
+TEST (1, [d(2)][d(1)],   Init ({{1}, {2, 3}}),    true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}}),      true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [d(2)][d(1)],   Init ({{1, 2}, {3, 4}}), true);
+
+TEST (1, [d(2)][d(2)],   Init (),                       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}}),                  false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}}),               false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3}}),          false);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4}}),       false);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4}}),       true);
+TEST (1, [d(2)][d(2)],   Init ({{1}, {2, 3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2}, {3, 4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5}}),    true);
+TEST (1, [d(2)][d(2)],   Init ({{1, 2, 3}, {4, 5, 6}}), true);
+
+TEST (1, [d(2)][d(3)],   Init (),                          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}}),                     false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}}),                  false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3}}),             false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4}}),          false);
+TEST (1, [d(2)][d(3)],   Init ({{1}, {2, 3, 4, 5}}),       true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2}, {3, 4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5}}),       false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6}}),    false);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3}, {4, 5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4}, {5, 6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5}, {6, 7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6}, {7}}), true);
+TEST (1, [d(2)][d(3)],   Init ({{1, 2, 3, 4, 5, 6, 7}}),   true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+TEST (1, [d(1)][d(MAX)], Init (),                              false);
+TEST (1, [d(1)][d(MAX)], Init ({}),                            false);
+TEST (1, [d(1)][d(MAX)], Init ({{1}}),                         false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2}}),                      false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(1)][d(MAX)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+
+TEST (1, [d(2)][d(MAX / 2)], Init (),                              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}}),                         false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}}),                      false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}}),                   false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4}}),                false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5}}),             false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6}}),          false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7}}),       false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8}}),    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3, 4, 5, 6, 7, 8, 9}}), false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2}}),                    false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1}, {2, 3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3}}),                 false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2}, {3, 4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4}}),              false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5}}),           false);
+TEST (1, [d(2)][d(MAX / 2)], Init ({{1, 2, 3}, {4, 5, 6}}),        false);
+#endif
+
+TEST (1, [d(2)][d(MAX)],        Init (),                         true);
+TEST (1, [d(2)][d(MAX)],        Init ({{1}}),                    true);
+TEST (1, [d(MAX)][d(MAX)],      Init ({{1, 2}}),                 true);
+TEST (1, [d(0)][d(MAX)],        Init ({{1}, {2}}),               true);
+TEST (1, [d(INT_MAX)][d(MAX)],  Init ({{1}, {2, 3}}),            true);
+TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1, 2}, {3, 4}, {5}}),    true);
+
+// Erroneous two-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2], Init (), true);
+
+// Verify that the unspecified bound is factored into the computation
+// of the total size.
+TEST ( 1, [][d(SIZE_MAX/2)],  Init ({{1}, {2}}),      true);
+TEST ( 2, [][d(SIZE_MAX/4)],  Init ({{1}, {2}}),      true);
+TEST ( 4, [][d(SIZE_MAX/8)],  Init ({{1}, {2}}),      true);
+TEST ( 8, [][d(SIZE_MAX/16)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/32)], Init ({{1}, {2}}),      true);
+TEST (16, [][d(SIZE_MAX/64)], Init ({{1}, {2}, {3}}), true);
+
+// Three dimensional VLAs with two constant bounds.
+
+TEST (1, [1][1][d(-1)], Init (),                    true);
+TEST (1, [1][1][d(0)], Init (),                     true);
+
+#if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (1, [1][1][d(0)],  Init ({}),                   true);
+TEST (1, [1][1][d(-1)], Init ({{}}),                 true);
+TEST (1, [1][d(-1)][1], Init ({{}}),                 true);
+TEST (1, [d(-1)][1][1], Init ({{}}),                 true);
+
+TEST (1, [1][1][d(0)], Init ({{}}),                  true);
+TEST (1, [1][d(0)][1], Init ({{}}),                  true);
+TEST (1, [d(0)][1][1], Init ({{}}),                  true);
+#endif
+
+TEST (1, [1][1][d(1)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(1)], Init ({{}}),                  false);
+TEST (1, [1][1][d(1)], Init ({{{}}}),                false);
+TEST (1, [1][1][d(1)], Init ({{{1}}}),               false);
+#endif
+
+TEST (1, [1][1][d(1)], Init ({{{1, 2}}}),            true);
+TEST (1, [1][1][d(1)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(1)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(1)][1], Init ({{}}),                  false);
+TEST (1, [1][d(1)][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][d(1)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}}}),          true);
+TEST (1, [1][d(1)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(1)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(1)][1][1], Init ({{}}),                  false);
+TEST (1, [d(1)][1][1], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [d(1)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}}),        true);
+TEST (1, [d(1)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][1][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][1][d(2)], Init ({{}}),                  false);
+TEST (1, [1][1][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][1][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][1][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][d(2)][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][d(2)][1], Init ({{}}),                  false);
+TEST (1, [1][d(2)][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [1][d(2)][1], Init ({{{1}}}),               false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][d(2)][1], Init ({{{1}, {2}, {3}}}),     true);
+
+TEST (1, [d(2)][1][1], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [d(2)][1][1], Init ({{}}),                  false);
+TEST (1, [d(2)][1][1], Init ({{{}}}),                false);
+#endif
+TEST (1, [d(2)][1][1], Init ({{{1}}}),               false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}}),        false);
+TEST (1, [d(2)][1][1], Init ({{{1}}, {{2}}, {{3}}}), true);
+
+TEST (1, [1][2][d(2)], Init (),                      false);
+
+#if !BUG_58646
+TEST (1, [1][2][d(2)], Init ({{}}),                  false);
+TEST (1, [1][2][d(2)], Init ({{{}}}),                false);
+#endif
+
+TEST (1, [1][2][d(2)], Init ({{{1}}}),               false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}}}),            false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}}}),         true);
+
+TEST (1, [1][2][d(2)], Init ({{{1}, {2}}}),          false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3}}}),       false);
+TEST (1, [1][2][d(2)], Init ({{{1, 2}, {3, 4}}}),    false);
+TEST (1, [1][2][d(2)], Init ({{{1}, {2, 3, 4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {}}}),     true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3}, {4}}}),    true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}}}),      true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),  true);
+TEST (1, [1][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}), true);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}}),                         false);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}}}),                           false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3}}}),                      false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}}),                   false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5}}}),            false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}}}),         false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7}}}),    false);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}), false);
+
+TEST (1, [2][2][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][2][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][2][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+
+// Three dimensional VLAs with one constant bound.
+TEST (1, [2][d(-1)][d(-1)], Init (),                                      true);
+TEST (1, [2][d(-1)][d(0)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(-1)],  Init (),                                      true);
+TEST (1, [2][d(1)][d(0)],   Init (),                                      true);
+TEST (1, [2][d(-1)][d(1)],  Init (),                                      true);
+TEST (1, [2][d(0)][d(1)],   Init (),                                      true);
+
+TEST (1, [2][d(2)][d(2)], Init (),                                        false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}}}),                                 false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2}}}),                            false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3}}}),                         false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}}),                      false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}),    false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [ ][d(2)][d(2)], Init ({{{1}, {2, 3, 4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4}}}),                      true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}}}),                        true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3, 4}, {5}}}),                   true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6}, {7, 8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4}}, {{5, 6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3, 4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9}}}), true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}}, {{3}, {4, 5, 6}}}),          true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}}, {{2}, {3, 4, 5, 6}}}),            true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2}, {3}}}),                       true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}, {4}}}),                    true);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3, 4}, {5}}}),                 true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+// Very large but not erroneous three-dimensional VLAs.
+TEST ( 1, [2][d(1)][d(MAX/2)], Init (),  false);
+TEST ( 2, [2][d(1)][d(MAX/4)], Init (),  false);
+TEST ( 4, [2][d(1)][d(MAX/8)], Init (),  false);
+TEST ( 8, [2][d(1)][d(MAX/16)], Init (), false);
+TEST (16, [2][d(1)][d(MAX/32)], Init (), false);
+
+TEST ( 1, [2][d(MAX/2)][d(1)], Init (),  false);
+TEST ( 2, [2][d(MAX/4)][d(1)], Init (),  false);
+TEST ( 4, [2][d(MAX/8)][d(1)], Init (),  false);
+TEST ( 8, [2][d(MAX/16)][d(1)], Init (), false);
+TEST (16, [2][d(MAX/32)][d(1)], Init (), false);
+
+TEST ( 1, [d(MAX/2)][2][d(1)], Init (),  false);
+TEST ( 2, [d(MAX/4)][2][d(1)], Init (),  false);
+TEST ( 4, [d(MAX/8)][2][d(1)], Init (),  false);
+TEST ( 8, [d(MAX/16)][2][d(1)], Init (), false);
+TEST (16, [d(MAX/32)][2][d(1)], Init (), false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// Erroneous three-dimensional VLAs with size exceeding SIZE_MAX / 2
+// (those must be rejected because no object can be bigger than that,
+// otherwise pointer arithmetic breaks).
+TEST ( 1, [2][d(1)][d(SIZE_MAX/2)],  Init (), true);
+TEST ( 2, [2][d(1)][d(SIZE_MAX/4)],  Init (), true);
+TEST ( 4, [2][d(1)][d(SIZE_MAX/8)],  Init (), true);
+TEST ( 8, [2][d(1)][d(SIZE_MAX/16)], Init (), true);
+TEST (16, [2][d(1)][d(SIZE_MAX/32)], Init (), true);
+
+TEST ( 1, [2][d(SIZE_MAX/2)][d(1)],  Init (), true);
+TEST ( 2, [2][d(SIZE_MAX/4)][d(1)],  Init (), true);
+TEST ( 4, [2][d(SIZE_MAX/8)][d(1)],  Init (), true);
+TEST ( 8, [2][d(SIZE_MAX/16)][d(1)], Init (), true);
+TEST (16, [2][d(SIZE_MAX/32)][d(1)], Init (), true);
+
+TEST ( 1, [d(SIZE_MAX/2)][2][d(1)],  Init (), true);
+TEST ( 2, [d(SIZE_MAX/4)][2][d(1)],  Init (), true);
+TEST ( 4, [d(SIZE_MAX/8)][2][d(1)],  Init (), true);
+TEST ( 8, [d(SIZE_MAX/16)][2][d(1)], Init (), true);
+TEST (16, [d(SIZE_MAX/32)][2][d(1)], Init (), true);
+
+TEST (16, [3][d(SIZE_MAX)][d(SIZE_MAX)], Init (), true);
+TEST (32, [d(SIZE_MAX)][5][d(SIZE_MAX)], Init (), true);
+TEST (64, [d(SIZE_MAX)][d(SIZE_MAX)][7], Init (), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644 (file)
index 0000000..f938f3b
--- /dev/null
@@ -0,0 +1,99 @@
+// Test to verify that variable length arrays the product of whose constant
+// bounds overflows or exceeds the implementation-defined limit are diagnosed.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-error=vla" }
+
+#define INT_MAX    __INT_MAX__
+#define LONG_MAX   __LONG_MAX__
+#define SIZE_MAX   __SIZE_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+#define MAX (SIZE_MAX / 2)
+
+void test (int x)
+{
+  const size_t amax = MAX;
+
+  // The following are valid and shouldn't elicit a bounds overflow warning.
+  {
+    char a [x][amax];         // { dg-warning "forbids" }
+    (void)a;
+  }
+
+  {
+    char a [amax][x];         // { dg-warning "forbids" }
+    (void)a;
+  }
+
+  // The following is invalid and should be diagnosed.  Unfortunately,
+  // when the VLA maximum size is (SIZE_MAX / 2), G++ also issues
+  // a (bogus) -Woverflow because it computes the array bound in
+  // a signed type (ssize_t) instead of size_t, in addition to
+  // rejecting the declaration with error: size of array ‘a’ is too
+  // large, before the VLA constant bound check has had a chance to
+  // see it.  So the test is disabled.
+  // {
+  //   char a [x][amax + 1];
+  //   (void)a;
+  // }
+
+  {
+    char a [x][x][amax];      // { dg-warning "forbids" }
+    (void)a;
+  }
+
+  {
+    char a [x][amax][x];      // { dg-warning "forbids" }
+    (void)a;
+  }
+
+  {
+    char a [amax][x][x];      // { dg-warning "forbids" }
+    (void)a;
+  }
+
+  {
+    char a [2][x][amax];      // { dg-warning "forbids|exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    // Unfortunately, the following is rejected with a different error
+    // earlier during parsing and before the VLA checking gets to see
+    // it: error: size of array ‘a’ is too large
+    // Ditto for other multidimensional VLAs where the overflow occurs
+    // in the computation of the product of adjacent constant bounds.
+    // char a [x][amax][amax];
+    // char b [x][2][amax];
+    // That error above also leads to the following error when using
+    // the variable below.
+    //   error:’ was not declared in this scope
+    // (void)a;
+  }
+
+  {
+    char a [amax][x][amax];   // { dg-warning "forbids|exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    char a [amax][amax][x];   // { dg-warning "forbids|exceeds maximum" }
+    (void)a;
+  }
+
+  {
+    struct A256 { __attribute__ ((aligned (256))) char a; };
+
+    enum {
+      M = 1024,
+      N = MAX / (sizeof (A256) * M)
+    };
+
+    A256 a [x][M][x][N];      // { dg-warning "forbids" }
+    (void)a;
+
+    A256 b [2][x][M][x][N];   // { dg-warning "forbids|exceeds maximum" }
+    (void)b;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644 (file)
index 0000000..d473a63
--- /dev/null
@@ -0,0 +1,260 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// or character array that's longer than the non-constant (runtime) bound
+// of the VLA causes an exception to be thrown.  For a compile-time version
+// of the test see vla14.C.
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-Wno-vla" }
+
+#pragma GCC diagnostic ignored "-Wvla"
+
+#define SIZE_MAX   __SIZE_MAX__
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.  Unless the maximum size is
+// obscenely large, smaller objects should be successfully created
+// provided there's enough stack space.  See TEST_NEAR_VLA_MAX_SIZE
+// below.
+#define MAX   (__SIZE_MAX__ / 2)
+
+// Define to non-zero to exercise very large VLAs with size just
+// below the implementation-defined maximum.
+#define TEST_NEAR_VLA_MAX_SIZE    0
+
+// Define to zero to enable tests that cause an ICE due to c++/58646.
+#define BUG_58646 1
+
+// Define to zero to enable tests that cause an ICE due to c++/69487.
+#define BUG_69487 1
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+template <class T>
+T d (T n)
+{
+  return n;
+}
+
+// Verify either that an expected exception has been thrown or that
+// one hasn't been thrown if one isn't expected.
+int __attribute__ ((noclone, noinline))
+sink (void *p, int line, bool expect, const char *expr)
+{
+  if (!p != expect)
+    {
+      __builtin_printf ("line %i: Assertion failed: '%s': "
+                        "exception unexpectedly %sthrown\n",
+                        line, expr, !p ? "" : "not ");
+      ++fail;
+    }
+  else
+    {
+#if defined DEBUG && DEBUG
+    __builtin_printf ("line %i: Assertion passed: '%s': "
+                     "exception %sthrown as expected\n",
+                     line, expr, !p ? "" : "not ");
+#endif
+    }
+  return 0;
+}
+
+template <class T, int>
+int test ();
+
+#define _CAT(name, line) name ## line
+#define CAT(name, line) _CAT (name, line)
+
+#define STR(...) #__VA_ARGS__
+
+// Macro to define a unique specialization of a function template to
+// exercise a VLA of type T, rank N, with dimensions given by Dims
+// and initializer Init.  Expect is true when the VLA initialization
+// is expected to trigger an exception.
+// The macro creates a unique global dummy int object and initializes
+// it with the result of the function.  The dummy object servers no
+// other purpose but to call the function.  The function verifies
+// the expected postconditions.
+#define TEST(T, Dims, Init, Expect)                                     \
+  template <>                                                           \
+  int test<T, __LINE__>()                                               \
+  {                                                                     \
+    const char str[] = "char a" #Dims " = { " STR (Init) " }";          \
+    try {                                                               \
+      T a Dims = { Init };                                              \
+      return sink (a, __LINE__, Expect, str);                           \
+    }                                                                   \
+    catch (...) {                                                       \
+      return sink (0, __LINE__, Expect, str);                           \
+    }                                                                   \
+  }                                                                     \
+  const int CAT (dummy, __LINE__) = test<T, __LINE__>()
+
+
+// Create and run a test function exercising a VLA definition
+//    +-- Element Type
+//    |     +-- VLA Dimensions
+//    |     |        +-- VLA Initializer
+//    |     |        |
+//    |     |        |             +-- Expect Exception
+//    |     |        |             |
+//    V     V        V             V
+TEST (char, [d(-1)], "",           true);
+
+TEST (char, [d(0)],  "",           true);
+TEST (char, [d(0)],  (""),         true);
+
+TEST (char, [d(1)],  "",           false);
+TEST (char, [d(1)],  (""),         false);
+
+TEST (char, [d(1)],  "1",          true);
+TEST (char, [d(1)],  ("1"),        true);
+
+TEST (char, [d(1)],  "12",         true);
+TEST (char, [d(1)],  "1234567890", true);
+
+TEST (char, [d(2)], "",           false);
+TEST (char, [d(2)], (""),         false);
+
+TEST (char, [d(2)], "1",          false);
+TEST (char, [d(2)], "12",         true);
+TEST (char, [d(2)], "123",        true);
+TEST (char, [d(2)], "1234567890", true);
+
+TEST (char, [d(3)], "",           false);
+TEST (char, [d(3)], "1",          false);
+TEST (char, [d(3)], "12",         false);
+TEST (char, [d(3)], "123",        true);
+TEST (char, [d(3)], "1234",       true);
+TEST (char, [d(3)], "1234567890", true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+
+#  if !BUG_69487
+// The following crash due to c++/69487.
+TEST (char, [d(MAX)], "",           false);
+TEST (char, [d(MAX)], "1",          false);
+TEST (char, [d(MAX)], "12",         false);
+TEST (char, [d(MAX)], "1234567890", false);
+#  endif
+
+TEST (char, [d(MAX)], Init (),                             false);
+TEST (char, [d(MAX)], Init (1),                            false);
+TEST (char, [d(MAX)], Init (1, 2),                         false);
+TEST (char, [d(MAX)], Init (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), false);
+#endif
+
+TEST (char, [d(SIZE_MAX / 2 + 1)], "", true);
+TEST (char, [d(SIZE_MAX - 2)],     "", true);
+TEST (char, [d(SIZE_MAX - 1)],     "", true);
+
+TEST (wchar_t, [d(1)], L"",           false);
+TEST (wchar_t, [d(1)], (L""),         false);
+TEST (wchar_t, [d(1)], L"1",          true);
+TEST (wchar_t, [d(1)], L"12",         true);
+TEST (wchar_t, [d(1)], L"1234567890", true);
+
+TEST (wchar_t, [d(2)], L"",           false);
+TEST (wchar_t, [d(2)], L"1",          false);
+TEST (wchar_t, [d(2)], L"12",         true);
+TEST (wchar_t, [d(2)], L"123",        true);
+TEST (wchar_t, [d(2)], L"1234567890", true);
+
+TEST (char, [d(1)][d(1)], Init (""),        false);
+TEST (char, [1]   [d(1)], Init (""),        false);
+TEST (char, [d(1)][1],    Init (""),        false);
+
+TEST (char, [d(1)][d(1)], Init ("1"),       true);
+
+// The following is accepted at compile time but throws an exception
+// at runtime since in C++ a one-element array cannot be initialized
+// with a string literal of length one because there isn't room for
+// the terminating NUL
+TEST (char, [1][d(1)],    Init ("1"),       true);
+
+// The following is rejected at compile-time since a one-element array
+// cannot be initialized with a string literal of length one because
+// there isn't room for the terminating NUL (see vla14.C).
+// TEST (char, [d(1)][1],    Init ("1"),       false);
+
+TEST (char, [d(1)][d(1)], Init ("12"),      true);
+TEST (char, [d(1)][d(1)], Init ("1", "2"),  true);
+TEST (char, [d(1)][d(1)], Init ("1", "23"), true);
+
+TEST (char, [d(2)][d(2)], Init ("", ""),    false);
+TEST (char, [d(2)][d(2)], Init ("", "1"),   false);
+TEST (char, [d(2)][d(2)], Init ("1", ""),   false);
+TEST (char, [d(2)][d(2)], Init ("1", "1"),  false);
+TEST (char, [2][d(2)],    Init ("",  "1"),  false);
+TEST (char, [2][d(2)],    Init ("1", ""),   false);
+TEST (char, [2][d(2)],    Init ("1", "1"),  false);
+TEST (char, [d(2)][2],    Init ("",  "1"),  false);
+TEST (char, [d(2)][2],    Init ("1", ""),   false);
+TEST (char, [d(2)][2],    Init ("1", "1"),  false);
+
+TEST (char, [2][d(2)],    Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("1", "23"), true);
+TEST (char, [d(2)][d(2)], Init ("12","3"),  true);
+
+#if TEST_NEAR_VLA_MAX_SIZE
+#  if !BUG_69487
+   // The following crash due to c++/69487.
+TEST (char, [1][d(MAX)], Init (""),           false);
+TEST (char, [1][d(MAX)], Init ("1"),          false);
+TEST (char, [1][d(MAX)], Init ("12"),         false);
+TEST (char, [1][d(MAX)], Init ("1234567890"), false);
+#  endif
+
+#  if !BUG_58646
+// The following causes an ICE due to c++/58646.
+TEST (char, [1][d(MAX)], Init (),                               false);
+#  endif
+
+TEST (char, [1][d(MAX)], Init ({1}),                            false);
+TEST (char, [1][d(MAX)], Init ({1, 2}),                         false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3}),                      false);
+TEST (char, [1][d(MAX)], Init ({1, 2, 3, 4, 5, 6, 7, 8, 9, 0}), false);
+
+TEST (char, [d(MAX)][1], Init ({1}),                            false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}),                       false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}),                  false);
+TEST (char, [d(MAX)][1], Init ({1}, {2}, {3}, {4}, {5},
+                              {6}, {7}, {8}, {9}, {0}),        false);
+#endif   // TEST_NEAR_VLA_MAX_SIZE
+
+// The following are expected to throw due to excessive size.
+TEST (char, [2][d(MAX)], Init ({1}),                                 true);
+TEST (char, [2][d(MAX)], Init ({1, 2}),                              true);
+TEST (char, [2][d(MAX)], Init ({1}, {2}),                            true);
+TEST (char, [2][d(MAX)], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3}, {4, 5, 6}),                true);
+TEST (char, [2][d(MAX)], Init ({1, 2, 3, 4}, {5, 6, 7, 8}),          true);
+
+TEST (char, [d(MAX)][2], Init ({1}),                                 true);
+TEST (char, [d(MAX)][2], Init ({1, 2}),                              true);
+TEST (char, [d(MAX)][2], Init ({1}, {2}),                            true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}),                      true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}),              true);
+TEST (char, [d(MAX)][2], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}),      true);
+
+TEST (char, [d(MAX)][d(MAX)], Init ({1}),                            true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}),                         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1}, {2}),                       true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}),                 true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}),         true);
+TEST (char, [d(MAX)][d(MAX)], Init ({1, 2}, {3, 4}, {5, 6}, {7, 8}), true);
+
+int main ()
+{
+  if (fail)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla14.C b/gcc/testsuite/g++.dg/cpp1y/vla14.C
new file mode 100644 (file)
index 0000000..4a0e827
--- /dev/null
@@ -0,0 +1,48 @@
+// PR c++/70019 - VLA size overflow not detected
+// Compile-time test to verify that attempting to initialize a VLA with
+// a string that's longer than the VLA's constant bound is diagnosed at
+// compile time.  For a runtime version of the test see vla13.C.
+
+// { dg-do run }
+// { dg-additional-options "-Wno-vla" }
+
+
+void test (int n)
+{
+  char a1[n][1] = { { "a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a1;
+
+  char a2[1][n] = { { "a" } };
+  (void)a2;
+
+  char a3[n][1][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a3;
+
+  char a4[1][1][n] = { { { "a" } } };
+  (void)a4;
+
+  char a5[1][n][1] = { { { "a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a5;
+
+  char a6[n][1][n] = { { { "a" } } };
+  (void)a6;
+
+
+  wchar_t a7[n][1] = { { L"a" } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a7;
+
+  wchar_t a8[1][n] = { { L"a" } };
+  (void)a8;
+
+  wchar_t a9[n][1][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a9;
+
+  wchar_t a10[1][1][n] = { { { L"a" } } };
+  (void)a10;
+
+  wchar_t a11[][n][1] = { { { L"a" } } };   // { dg-error "initializer-string for array of chars is too long" }
+  (void)a11;
+
+  wchar_t a12[n][1][n] = { { { L"a" } } };
+  (void)a12;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla3.C b/gcc/testsuite/g++.dg/cpp1y/vla3.C
new file mode 100644 (file)
index 0000000..9b2d6b3
--- /dev/null
@@ -0,0 +1,43 @@
+// Test for throwing bad_array_length on invalid array length.
+// { dg-do run { target c++14 } }
+// { dg-additional-options "-Wno-vla" }
+
+namespace std
+{
+struct exception
+{
+  virtual ~exception ();
+  virtual const char* what () const throw ();
+};
+}
+
+int f(int i)
+{
+  int ar[i]{1,2,3,4};
+  return ar[i-1];
+}
+
+void g(int i)
+{
+  int ar[i];
+  ar[0] = 42;
+}
+
+int main()
+{
+  int ok = 0;
+  f(4);                                // OK
+  try {
+    f(3);                      // too small
+  }
+  catch (std::exception &e) {
+    ++ok;
+  }
+  try { g(-24); }              // negative
+  catch (std::exception &e) {
+    ++ok;
+  }
+
+  if (ok != 2)
+    __builtin_abort ();
+}
index 2d72df40382b681d984f0fb35e822d16509e58ff..fc10c0a7349f280c5062137a02460c47a377e98c 100644 (file)
@@ -3,5 +3,5 @@
 
 void foo(int i)
 {
-  int x[][i] = { 0 };
+  int x[][i] = { { 0 } };
 }
index 311cdb1d77a740e81ff245adb809437052603eca..374c80ad38413173e179bb24523eff6d5bc25309 100644 (file)
@@ -1,5 +1,8 @@
 // { dg-do run }
-// { dg-options "-Wno-vla -fsanitize=undefined" }
+// Disable exceptions to prevent the erroneous initializer from
+// throwing before the sanitizer instrumentation has detected
+// the problem.
+// { dg-options "-Wno-vla -fno-exceptions -fsanitize=undefined" }
 // { dg-output "index 1 out of bounds" }
 
 void f(int i) {
index 2abb015006d4e93bb50bda886268e1006b03ee1f..d31a5d29120fe18e041b187c3f40a2c311ac516b 100644 (file)
@@ -1,3 +1,9 @@
+2016-04-13  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69517
+       * testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
+       upper bound is positive.
+
 2016-04-13  Jonathan Wakely  <jwakely@redhat.com>
 
        * include/bits/c++config (_GLIBCXX_BEGIN_NAMESPACE_EMPTY_TYPES,
index d9d1f2a44ca6b3f8f217cdbebfc92d5bb64e749c..f944236f0617c3d80badf6a6d29072f07f7f1d35 100644 (file)
@@ -44,7 +44,8 @@ template<typename Con>
   {
     bool test __attribute__((unused)) = true;
 
-    rvalstruct array[length];
+    /* Make sure the VLA upper bound is positive. */
+    rvalstruct array[length + 1];
     for(int i = 0; i < length; ++i)
       array[i] = i;
     Con con(array, array + length);