aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2016-04-13 23:26:41 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2016-04-13 17:26:41 -0600
commit342fac9537c6a75e65fe62943ba84b81bddede3f (patch)
tree1d55385c5ee07d32a08d9279dcb595632d96e73c
parent2ecc0c837bf2ac1309f41d30b7b30595331a6eb6 (diff)
downloadgcc-342fac9537c6a75e65fe62943ba84b81bddede3f.zip
gcc-342fac9537c6a75e65fe62943ba84b81bddede3f.tar.gz
gcc-342fac9537c6a75e65fe62943ba84b81bddede3f.tar.bz2
PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
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
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/cp/ChangeLog16
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c45
-rw-r--r--gcc/cp/init.c315
-rw-r--r--gcc/cp/typeck2.c4
-rw-r--r--gcc/doc/extend.texi38
-rw-r--r--gcc/testsuite/ChangeLog14
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-1.c30
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla11.C711
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla12.C99
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla13.C260
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla14.C48
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla3.C43
-rw-r--r--gcc/testsuite/g++.dg/init/array24.C2
-rw-r--r--gcc/testsuite/g++.dg/ubsan/vla-1.C5
-rw-r--r--libstdc++-v3/ChangeLog6
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc3
18 files changed, 1628 insertions, 20 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 26db5fe..a3c6c12 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c9929b63..866b4f2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8d721c7..87e3ea0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7099199..42e853f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 5997d53..ec19d72 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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;
+}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index b921689..eba19ca 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -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
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a5a8b23..6687d59 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5e047c6..b07b8b2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index 52ade3a..27ef110 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -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
index 0000000..af9624a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -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
index 0000000..f938f3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -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
index 0000000..d473a63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -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
index 0000000..4a0e827
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -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
index 0000000..9b2d6b307
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla3.C
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/init/array24.C b/gcc/testsuite/g++.dg/init/array24.C
index 2d72df4..fc10c0a 100644
--- a/gcc/testsuite/g++.dg/init/array24.C
+++ b/gcc/testsuite/g++.dg/init/array24.C
@@ -3,5 +3,5 @@
void foo(int i)
{
- int x[][i] = { 0 };
+ int x[][i] = { { 0 } };
}
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
index 311cdb1..374c80a 100644
--- a/gcc/testsuite/g++.dg/ubsan/vla-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -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) {
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 2abb015..d31a5d2 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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,
diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
index d9d1f2a..f944236 100644
--- a/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/moveable2.cc
@@ -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);