PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
PR c++/70019 - VLA size overflow not detected
gcc/testsuite/ChangeLog:
2016-04-01 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
* 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-01 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
* decl.c (vla_p, throw_bad_array_length, build_vla_check_size,
build_vla_check_init, build_vla_check): New functions.
(check_initializer, cp_finish_decl): Call them.
(reshape_init_r): Reject incompletely braced intializer-lists
for VLAs.
gcc/doc/ChangeLog:
2016-04-01 Martin Sebor <msebor@redhat.com>
PR c++/69517
PR c++/70019
* extend.texi (Variable Length): Document C++ specifics.
libstdc++-v3/ChangeLog:
2016-04-01 Martin Sebor <msebor@redhat.com>
PR c++/69517
* testsuite/25_algorithms/rotate/moveable2.cc: Make sure VLA
upper bound is positive.
@@ -106,6 +106,21 @@ static tree build_cp_library_fn (tree, enum tree_code, tree, int);
static void store_parm_decls (tree);
static void initialize_local_var (tree, tree);
static void expand_static_init (tree, tree);
+static bool vla_p (tree);
+static tree build_vla_check (tree, tree = NULL_TREE);
+
+/* Call __cxa_throw_bad_array_length to indicate that the size calculation
+ 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);
+}
/* The following symbols are subsumed in the cp_global_trees array, and
listed here individually for documentation purposes.
@@ -5852,6 +5867,16 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
}
}
+ if (vla_p (type))
+ {
+ /* 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);
}
@@ -6155,6 +6180,32 @@ 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));
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && vla_p (type)
+ && !processing_template_decl)
+ {
+ /* Statically check for overflow in VLA bounds and build
+ an expression that checks whether the VLA is erroneous
+ at runtime, either due to invalid (runtime) bounds or
+ due to excess initializers for the runtime bounds. */
+ tree check = build_vla_check (TREE_TYPE (decl), init);
+
+ 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);
+ }
+ }
init = NULL;
}
}
@@ -6510,6 +6561,253 @@ notice_forced_label_r (tree *tp, int *walk_subtrees, void *)
return NULL_TREE;
}
+/* The implementation of build_vla_check() that recursively builds
+ an expression to determine whether the VLA TYPE is erroneous.
+ 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 constant dimensions of the array. */
+
+static tree
+build_vla_size_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);
+
+ tree check = boolean_false_node;
+
+ 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. */
+ tree subcheck = build_vla_size_check (TREE_TYPE (type),
+ vlasize, max_vlasize,
+ cst_size);
+ check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+ check, subcheck);
+ }
+ 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. */
+ 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 it's zero or negative. */
+ tree zerocheck = fold_build2 (LE_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 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.
+ INIT is the VLA initializer expression to check against TYPE. */
+
+static tree
+build_vla_init_check (tree type, tree init)
+{
+ tree check = boolean_false_node;
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ /* Compute the upper bound of this array type. */
+ tree inner_nelts = 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);
+ check = fold_build2 (LT_EXPR, boolean_type_node, inner_nelts,
+ initelts);
+
+ 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)
+ {
+ tree subcheck = build_vla_init_check (TREE_TYPE (type),
+ ce->value);
+
+ check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+ check, subcheck);
+ }
+ }
+ }
+ 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. */
+
+static tree
+build_vla_check (tree type, tree init /* = NULL_TREE */)
+{
+ /* This is the initial (non-recursive) call to the function.
+ Build a variable storing the total runtime size of the VLA. */
+ 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) = size_one_node;
+ layout_decl (vlasize, 0);
+ vlasize = pushdecl (vlasize);
+ cp_finish_decl (vlasize, size_one_node, true, NULL_TREE, 0);
+
+ /* Impose a limit on the size of the biggest VLA in bytes. */
+ tree max_vlasize
+ = fold_build2 (LSHIFT_EXPR, size_type_node, size_one_node,
+ wide_int_to_tree (size_type_node, 20) /* 1 MB */);
+
+ /* The product of all constant dimensions of the VLA shared by recursive
+ invocations of the function. */
+ offset_int cst_size = 1;
+
+ /* Build an expression that checks the runtime bounds of the VLA for
+ invalid values and the size of the VLA for overflow. */
+ tree check
+ = build_vla_size_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. */
+ tree init_check
+ = build_vla_init_check (type, init);
+
+ check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+ init_check);
+ }
+
+ return check;
+}
+
+/* Return true when either T is a variably modified array type,
+ or (recursively) when T is an array of variable modified types. */
+static bool
+vla_p (tree t)
+{
+ if (array_of_runtime_bound_p (t))
+ return true;
+
+ if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ return vla_p (TREE_TYPE (t));
+
+ return false;
+}
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
@@ -6630,21 +6928,24 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
}
}
- if (init && VAR_P (decl))
+ if (VAR_P (decl))
{
- DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
- /* If DECL is a reference, then we want to know whether init is a
- reference constant; init_const_expr_p as passed tells us whether
- it's an rvalue constant. */
- if (TREE_CODE (type) == REFERENCE_TYPE)
- init_const_expr_p = potential_constant_expression (init);
- if (init_const_expr_p)
+ if (init)
{
- /* Set these flags now for templates. We'll update the flags in
- store_init_value for instantiations. */
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
- if (decl_maybe_constant_var_p (decl))
- TREE_CONSTANT (decl) = 1;
+ DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
+ /* If DECL is a reference, then we want to know whether init is a
+ reference constant; init_const_expr_p as passed tells us whether
+ it's an rvalue constant. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ init_const_expr_p = potential_constant_expression (init);
+ if (init_const_expr_p)
+ {
+ /* Set these flags now for templates. We'll update the flags in
+ store_init_value for instantiations. */
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
+ if (decl_maybe_constant_var_p (decl))
+ TREE_CONSTANT (decl) = 1;
+ }
}
}
@@ -6797,6 +7098,33 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
cleanups = make_tree_vector ();
init = check_initializer (decl, init, flags, &cleanups);
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && vla_p (type)
+ && !processing_template_decl)
+ {
+ /* Statically check for overflow in VLA bounds and build
+ an expression that checks whether the VLA is erroneous
+ at runtime. */
+ tree check = build_vla_check (type);
+
+ if (cxx_dialect >= cxx11
+ && flag_exceptions
+ && current_function_decl
+ /* Avoid instrumenting constexpr functions. Those must
+ be checked statically, and the (non-constexpr) dynamic
+ instrumentation would cause them to be rejected. */
+ && !DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ {
+ /* Use the runtime check only in C++ 11 mode and later
+ and 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);
+ }
+ }
+
/* Handle:
[dcl.init]
@@ -1634,14 +1634,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 1 MB, 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
@@ -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;
}
new file mode 100644
@@ -0,0 +1,621 @@
+// 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)
+
+// Undefine 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__
+
+// The size of the largest allowed VLA in bytes. Bigger objects
+// cause an exception to be thrown.
+#define MAX (1 << 20)
+
+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);
+
+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);
+
+// Very large but not erroneous one dimensional VLAs.
+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);
+
+// Excessively large one dimensional VLAs.
+TEST (1, [d(LONG_MIN)], Init (), true);
+TEST (1, [d(INT_MIN)], Init (), true);
+TEST (1, [d(-1)], Init (), true);
+TEST (1, [d(INT_MAX)], Init (), true);
+TEST (1, [d(LONG_MAX)], Init (), true);
+TEST (1, [d(UINT_MAX)], Init (), true);
+TEST (1, [d(ULONG_MAX)], Init (), true);
+TEST (1, [d(SIZE_MAX)], Init (), true);
+
+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(LONG_MIN)], Init ({}), true);
+TEST (1, [d(INT_MIN)], Init ({}), true);
+TEST (1, [d(-1)], Init ({}), true);
+TEST (1, [d(INT_MAX)], Init ({}), true);
+TEST (1, [d(LONG_MAX)], Init ({}), true);
+TEST (1, [d(UINT_MAX)], Init ({}), true);
+TEST (1, [d(ULONG_MAX)], 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(INT_MAX)], Init ({0}), true);
+TEST (1, [d(LONG_MAX)], Init ({0}), true);
+TEST (1, [d(UINT_MAX)], Init ({0}), true);
+TEST (1, [d(ULONG_MAX)], Init ({0}), true);
+TEST (1, [d(SIZE_MAX)], Init ({0}), 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, [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, [1][d(2)], Init (), false);
+TEST (1, [1][d(2)], Init ({{1}}), false);
+TEST (1, [1][d(2)], Init ({{1, 2}}), false);
+TEST (1, [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, [2][d(1)], Init ({{1}, {2}}), false);
+TEST (1, [2][d(1)], Init ({{1, 2}}), true);
+TEST (1, [2][d(1)], Init ({{1}, {2, 3}}), true);
+TEST (1, [2][d(1)], Init ({{1, 2, 3}}), true);
+TEST (1, [2][d(1)], Init ({{1, 2, 3}, {4}}), true);
+TEST (1, [2][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);
+
+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);
+
+// 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(INT_MAX)], Init (), true);
+TEST (1, [1][d(LONG_MAX)], Init (), true);
+TEST (1, [1][d(UINT_MAX)], Init (), true);
+TEST (1, [1][d(ULONG_MAX)], 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(INT_MAX)], Init ({}), true);
+TEST (1, [1][d(LONG_MAX)], Init ({}), true);
+TEST (1, [1][d(UINT_MAX)], Init ({}), true);
+TEST (1, [1][d(ULONG_MAX)], 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(INT_MAX)], Init ({{0}}), true);
+TEST (1, [1][d(LONG_MAX)], Init ({{0}}), true);
+TEST (1, [1][d(UINT_MAX)], Init ({{0}}), true);
+TEST (1, [1][d(ULONG_MAX)], 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(INT_MAX)][1], Init (), true);
+TEST (1, [d(LONG_MAX)][1], Init (), true);
+TEST (1, [d(UINT_MAX)][1], Init (), true);
+TEST (1, [d(ULONG_MAX)][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(INT_MAX)][1], Init ({}), true);
+TEST (1, [d(LONG_MAX)][1], Init ({}), true);
+TEST (1, [d(UINT_MAX)][1], Init ({}), true);
+TEST (1, [d(ULONG_MAX)][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(INT_MAX)][1], Init ({{0}}), true);
+TEST (1, [d(LONG_MAX)][1], Init ({{0}}), true);
+TEST (1, [d(UINT_MAX)][1], Init ({{0}}), true);
+TEST (1, [d(ULONG_MAX)][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);
+
+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);
+
+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}}), true);
+TEST (1, [d(0)][d(MAX)], Init ({{1}}), true);
+TEST (1, [d(INT_MAX)][d(MAX)], Init ({{1}}), true);
+TEST (1, [d(SIZE_MAX)][d(MAX)], Init ({{1}}), true);
+TEST (1, [d(INT_MAX)][d(INT_MAX)], Init ({{1}}), true);
+TEST (1, [d(LONG_MAX)][d(LONG_MAX)], Init ({{1}}), true);
+TEST (1, [d(SIZE_MAX)][d(SIZE_MAX)], Init ({{1}}), 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);
+#endif
+
+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);
+
+TEST (1, [1][1][d(1)], Init (), false);
+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);
+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);
+TEST (1, [1][d(1)][1], Init ({{}}), false);
+TEST (1, [1][d(1)][1], Init ({{{}}}), false);
+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);
+TEST (1, [d(1)][1][1], Init ({{}}), false);
+TEST (1, [d(1)][1][1], Init ({{{}}}), false);
+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);
+TEST (1, [1][1][d(2)], Init ({{}}), false);
+TEST (1, [1][1][d(2)], Init ({{{}}}), false);
+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);
+TEST (1, [1][d(2)][1], Init ({{}}), false);
+TEST (1, [1][d(2)][1], Init ({{{}}}), false);
+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);
+TEST (1, [d(2)][1][1], Init ({{}}), false);
+TEST (1, [d(2)][1][1], Init ({{{}}}), false);
+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);
+TEST (1, [1][2][d(2)], Init ({{}}), false);
+TEST (1, [1][2][d(2)], Init ({{{}}}), false);
+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, [2][d(2)][d(2)], Init ({{{1}, {2}}}), false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1}, {2, 3}}}), false);
+TEST (1, [2][d(2)][d(2)], Init ({{{1, 2}, {3}}}), false);
+TEST (1, [2][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, [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}}}), 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);
+
+// 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);
+
+int main ()
+{
+ if (fail)
+ __builtin_abort ();
+}
new file mode 100644
@@ -0,0 +1,69 @@
+// Test to verify that variable length arrays whose size overflows
+// or exceeds the implementation-defined limit is diagnosed.
+// { dg-do run { 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;
+
+void test (int x, int y, int z)
+{
+ const size_t amax = SIZE_MAX / 2;
+
+ {
+ char a [x][amax]; // { dg-warning "forbids|size of variable length array exceeds maximum" }
+ (void)a;
+ }
+
+ {
+ char a [amax][y]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ char a [x][y][amax]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ char a [x][amax][z]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ char a [amax][y][z]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ // Unfortunately, this 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
+ char a [x][amax][amax]; // { dg-error "size of array" }
+
+ // 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][y][amax]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ char a [amax][amax][z]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+
+ {
+ struct A256 { __attribute__ ((aligned (256))) char a; };
+
+ A256 a [x][1024][y][1024][z][1024][x][1024][z]; // { dg-warning "forbids|size of variable length array" }
+ (void)a;
+ }
+}
new file mode 100644
@@ -0,0 +1,223 @@
+// 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" }
+
+#define INT_MAX __INT_MAX__
+#define LONG_MAX __LONG_MAX__
+#define SIZE_MAX __SIZE_MAX__
+
+#define INT_MIN (-__INT_MAX__ - 1)
+#define LONG_MIN (-__LONG_MAX__ - 1)
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+// The size of the largest allowed VLA in bytes. Bigger objects
+// cause an exception to be thrown.
+#define MAX (1 << 20)
+
+typedef __SIZE_TYPE__ size_t;
+
+// Incremented for each test failure.
+int fail;
+
+// Used to convert a constant array dimension to a non-constant one.
+int d (int 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
+ {
+#ifdef 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)], "", false);
+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)], "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);
+
+// The following crash due to c++/70440.
+// TEST (char, [d(MAX)], "", false);
+// TEST (char, [d(MAX)], "1", false);
+// TEST (char, [d(MAX)], "12", false);
+// TEST (char, [d(MAX)], "1234567890", false);
+
+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);
+
+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);
+
+// The following crash due to c++/70440.
+// 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);
+
+// The following causes an ICE due to c++/58646.
+// TEST (char, [1][d(MAX)], Init (), false);
+
+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);
+
+// 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 ();
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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 ();
+}
@@ -3,5 +3,5 @@
void foo(int i)
{
- int x[][i] = { 0 };
+ int x[][i] = { { 0 } };
}
@@ -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) {
* Unmerged path gcc/testsuite/g++.dg/warn/overflow-warn-7.C
@@ -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);