public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements
@ 2016-03-07  1:38 Martin Sebor
  2016-03-14 21:26 ` Martin Sebor
  2016-03-23 18:34 ` Jason Merrill
  0 siblings, 2 replies; 22+ messages in thread
From: Martin Sebor @ 2016-03-07  1:38 UTC (permalink / raw)
  To: Gcc Patch List, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1956 bytes --]

GCC 4.9 had added support for C++ VLAs as specified in WG21
document N3639 expected to be included in C++ 14.  However,
WG21 ultimately decided not to include N3639 in C++ 14 and
the G++ support was partially removed in 5.1.  Unfortunately,
the removal rendered some safe albeit erroneous G++ 4.9 code
undefined.  This patch restores the well-defined behavior of
such code by having it throw an exception in response to
the erroneous conditions.

While testing the patch I found a number of other problems in
the G++ support for VLAs, including PR c++/70019 - VLA size
overflow not detected, which was never implemented (not even
in 4.9).  Since this is closely related to the regression
discussed in 69517 the patch also provides that support.

There are a few additional points to note about the patch:

1) It restores the std::bad_array_length exception from N3639,
    even though the class isn't specified by the C++ standard.
    At first I thought that introducing a different (private)
    type would be more appropriate, but in the end couldn't come
    up with a good argument for not keeping the same type.  Using
    the same type also allows programs that rely on the exception
    and that were built with GCC 4.9 to be ported to GCC 6 without
    change.

2) It hardwires a rather arbitrarily restrictive limit of 64 KB
    on the size of the biggest C++ VLA.  (This could stand to be
    improved and made more intelligent, and perhaps integrated
    with stack  checking via -fstack-limit, after the GCC 6
    release.)

3) By throwing an exception for erroneous VLAs the patch largely
    defeats the VLA Sanitizer.  The sanitizer is still useful in
    C++ 98 mode where the N3639 VLA runtime checking is disabled,
    and when exceptions are disabled via -fno-exceptions.
    Disabling  the VLA checking in C++ 98 mode doesn't seem like
    a useful feature, but I didn't feel like reverting what was
    a deliberate decision.

Martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gcc-69517.patch --]
[-- Type: text/x-patch; name="gcc-69517.patch", Size: 43533 bytes --]

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-03-06  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.
	* g++.dg/ubsan/vla-1.C: Disable exceptions.

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

	PR c++/69517
	PR c++/70019
	* decl.c (vla_p, throw_bad_array_length, build_vla_check): New
	functions.
	(check_initializer, cp_finish_decl): Call them.

gcc/doc/ChangeLog:

2016-03-06  Martin Sebor  <msebor@redhat.com>

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

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5ec6589..682828c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -106,6 +106,22 @@ 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, tree = NULL_TREE,
+			     tree = NULL_TREE, offset_int * = 0);
+
+/* 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.
@@ -6160,6 +6176,33 @@ 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 (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);
+		}
+	    }
 	  init = NULL;
 	}
     }
@@ -6499,6 +6542,226 @@ is_concept_var (tree decl)
           && DECL_DECLARED_CONCEPT_P (decl));
 }
 
+/* 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.
+   VLASIZE is initially expected to be NULL_TREE and is used internally
+   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.  A default
+   value is hardcoded by the function when MAX_VLASIZE is initially NULL.
+   CST_SIZE, initially ignored, is the product of the constant dimensions
+   of the array.  */
+
+static tree
+build_vla_check (tree type,
+		 tree init /* = NULL_TREE */,
+		 tree vlasize /* NULL_TREE */,
+		 tree max_vlasize /* = NULL_TREE */,
+		 offset_int *cst_size /* = 0 */)
+{
+  /* The product of all constant dimensions of the VLA shared by recursive
+     invocations of the function.  Set to 1 by the first call and reset
+     after the first error to avoid redundant diagnostics.  */
+  offset_int cst_size_data = 1;
+
+  tree vmul = builtin_decl_explicit (BUILT_IN_MUL_OVERFLOW);
+
+  if (vlasize == NULL_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);
+
+      cst_size = &cst_size_data;
+    }
+
+  /* Impose a size limit on the size of the biggest VLA in bytes.  */
+  if (max_vlasize == NULL_TREE)
+    max_vlasize = fold_convert (size_type_node,
+				build_all_ones_cst (uint16_type_node));
+
+  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;
+	}
+
+      size_t len;
+
+      if (init == NULL_TREE
+	  || (TREE_CODE (init) == CONSTRUCTOR && !CONSTRUCTOR_ELTS (init)))
+	{
+	  /* This array either has no initializer or the initializer is
+	     empty.  Check only for overflow in its (runtime) upper bounds.  */
+	  tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					     vlasize, vlasizeaddr);
+
+	  /* Recursively check for overflow in the remaining major bounds.  */
+	  tree subcheck = build_vla_check (TREE_TYPE (type), init,
+					   vlasize, max_vlasize,
+					   cst_size);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, vflowcheck);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			       check, subcheck);
+	}
+      else 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.  */
+	  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 (runtime) bounds of of the array type.  */
+	  FOR_EACH_VEC_SAFE_ELT (v, i, ce)
+	    {
+	      if (1) // !vec_safe_is_empty (CONSTRUCTOR_ELTS (ce->value)))
+		{
+		  tree subcheck = build_vla_check (TREE_TYPE (type),
+						   ce->value,
+						   vlasize, max_vlasize,
+						   cst_size);
+		  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+				       check, subcheck);
+		}
+	    }
+
+	  /* Check for overflow in runtime bounds.  */
+	  tree vflowcheck = build_call_expr (vmul, 3, inner_nelts,
+					     vlasize, vlasizeaddr);
+	  vflowcheck = fold_build2 (LT_EXPR, boolean_type_node,
+				    max_vlasize, vlasize);
+	  check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, check,
+			       vflowcheck);
+	}
+      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 ();
+	}
+    }
+  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.  */
+      tree vflowcheck = build_call_expr (vmul, 3, typesize,
+					 vlasize, vlasizeaddr);
+
+      /* Check to see if the size exceeds the maximum.  */
+      vflowcheck = fold_build2 (LT_EXPR, boolean_type_node,
+				max_vlasize, vlasize);
+
+      check = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
+			   check, vflowcheck);
+
+      /* 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.  The error takes
+	 precendence over the warning below.  */
+      *cst_size = 0;
+    }
+  else if (cst_size == &cst_size_data
+	   && 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);
+    }
+
+  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_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,
@@ -6619,21 +6882,50 @@ 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)
-	{
-	  /* 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;
+      if (init)
+	{
+	  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;
+	    }
+	}
+      else 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);
+	    }
 	}
     }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 10a42b6..a287dee 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1634,14 +1634,24 @@ 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, in C++ 11 mode and later, G++ instruments variable-length
+arrays with checks for erroneous uses: when a variable-length array
+object is created its bounds are checked to detect non-positive bounds,
+integer overflows, sizes in excess of 64 KB, 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}.
+
+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/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..4cdfbc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla11.C
@@ -0,0 +1,469 @@
+// PR c++/69517 - [5/6 regression] SEGV on a VLA with excess initializer
+//   elements
+// Test to verify that attempting to create an erroneous VLA or to
+// initialize a valid VLA with excess elements causes an exception
+// to be thrown.
+
+// { 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)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define VLA_SIZE_MAX   0xffffU
+
+typedef __SIZE_TYPE__ size_t;
+
+void __attribute__ ((noclone, noinline))
+sink (void*)
+{
+}
+
+template <class T>
+void __attribute__ ((noclone, noinline))
+test_vla (size_t rank, const long *dims, int init)
+{
+  switch (rank)
+    {
+    case 1:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 2:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 3:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]][dims [2]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]][dims [2]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]][dims [2]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    case 4:
+      switch (init)
+        {
+        case -1: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]];
+          sink (a);
+          break;
+        }
+        case 0: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { };
+          sink (a);
+          break;
+        }
+        case 1: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0 };
+          sink (a);
+          break;
+        }
+        case 2: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1 };
+          sink (a);
+          break;
+        }
+        case 3: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1, 2 };
+          sink (a);
+          break;
+        }
+        case 4: {
+          T a [dims [0]][dims [1]][dims [2]][dims [3]] = { 0, 1, 2, 3 };
+          sink (a);
+          break;
+        }
+        default:
+          __builtin_printf ("too many initializers in test\n");
+          __builtin_abort ();
+        }
+      break;
+
+    default:
+      __builtin_printf ("unexpected array rank in test\n");
+      __builtin_abort ();
+    }
+}
+
+// Compute whether a declaration of a VLA of the specified RANK
+// and the specified dimensions DIMS would overflow either due
+// to the dimensions exceeding the range of size_t or due to
+// the size of the object exceeding the maximum allowed VLA
+// size, or the size being zero.
+bool vflow (size_t tsize, int rank, const long *dims)
+{
+  size_t nbytes = tsize;
+
+  for (int i = 0; i < rank; ++i)
+    if (__builtin_mul_overflow (nbytes, dims [i], &nbytes))
+      return true;
+
+  return 0 == nbytes || VLA_SIZE_MAX < nbytes;
+}
+
+#define Aligned(N) __attribute__ ((aligned (N)))
+#define Packed     __attribute__ ((packed))
+
+struct Packed S1 { char i; };
+struct Packed S4 { Aligned (4) char i; };
+struct Packed S128 { Aligned (128) char i; };
+struct Packed S1024 { Aligned (1024) char i; };
+
+int main (void)
+{
+  static const struct {
+    int line;
+    void (*fun)(size_t, const long*, int);
+    size_t size;
+    int rank;
+    const long dims[8];
+    int init;
+    int except;
+  } test [] = {
+
+#define T(type) __LINE__, &test_vla<type>, sizeof (type)
+
+    // Rank-1 VLAs with no initializers.
+    // Valid:
+    { T (  S1), 1, {    1 }, -1, false },
+    { T (  S1), 1, {    2 }, -1, false },
+    { T (  S1), 1, {  256 }, -1, false },
+
+    { T (  S4), 1, {    1 }, -1, false },
+    { T (  S4), 1, {    2 }, -1, false },
+    { T (  S4), 1, {    3 }, -1, false },
+    { T (  S4), 1, {    4 }, -1, false },
+    { T (  S4), 1, {    5 }, -1, false },
+    { T (  S4), 1, {    6 }, -1, false },
+    { T (  S4), 1, {    7 }, -1, false },
+    { T (  S4), 1, {    8 }, -1, false },
+    { T (  S4), 1, { 1024 }, -1, false },
+    { T (  S4), 1, { 4096 }, -1, false },
+
+    // Valid with initializers.
+    { T (  S1), 1, {    1 },  1, false },
+    { T (  S1), 1, {    2 },  2, false },
+    { T (  S1), 1, {    3 },  3, false },
+    { T (  S1), 1, {    4 },  4, false },
+    { T (  S1), 1, {    5 },  4, false },
+    { T (  S1), 1, {  123 },  4, false },
+
+    // Possibly erroneous.
+    { T (S128), 1, { 4096 }, -1, -1 },
+
+    { T (  S1), 1, { VLA_SIZE_MAX >> 16 }, -1, -1 },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 15 }, -1, -1 },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 14 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 13 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 12 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 11 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 10 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 9 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 8 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 7 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 6 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 5 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 4 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 3 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 2 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 1 }, -1, false },
+    { T (  S1), 1, { VLA_SIZE_MAX >> 0 }, -1, false },
+
+    // Erroneous: size in excess of implementation-defined limit.
+    { T (S4), 1, { LONG_MIN }, -1, true },
+    { T (S4), 1, {  INT_MIN }, -1, true },
+    { T (S4), 1, {    -4096 }, -1, true },
+    { T (S4), 1, {    -1024 }, -1, true },
+    { T (S4), 1, {       -1 }, -1, true },
+    { T (S4), 1, {        0 }, -1, true },
+    { T (S4), 1, {  INT_MAX }, -1, true },
+    { T (S4), 1, { LONG_MAX }, -1, true },
+
+    // Erroneous: excess initializers.
+    { T (S1), 1, {        1 },  2, true },
+    { T (S1), 1, {        2 },  3, true },
+    { T (S1), 1, {        3 },  4, true },
+
+    // Rank-2 VLAs with no initializers.
+    // Valid:
+    { T (S4), 2, { 1,    1 }, -1, false },
+    { T (S4), 2, { 1,    2 }, -1, false },
+    { T (S4), 2, { 1,    3 }, -1, false },
+    { T (S4), 2, { 1,    4 }, -1, false },
+    { T (S4), 2, { 1,    5 }, -1, false },
+    { T (S4), 2, { 1,    6 }, -1, false },
+    { T (S4), 2, { 1,    7 }, -1, false },
+    { T (S4), 2, { 1,    8 }, -1, false },
+    { T (S4), 2, { 1, 1024 }, -1, false },
+    { T (S4), 2, { 1, 4096 }, -1, false },
+
+    { T (S4), 2, {  2,    1 }, -1, false },
+    { T (S4), 2, {  3,    2 }, -1, false },
+    { T (S4), 2, {  4,    3 }, -1, false },
+    { T (S4), 2, {  5,    4 }, -1, false },
+    { T (S4), 2, {  6,    5 }, -1, false },
+    { T (S4), 2, {  7,    6 }, -1, false },
+    { T (S4), 2, {  8,    7 }, -1, false },
+    { T (S4), 2, {  9,    8 }, -1, false },
+
+    // Possibly erroneous.
+    { T (S4), 2, { 10, 1024 }, -1, -1 },
+    { T (S4), 2, { 11, 4096 }, -1, -1 },
+
+    // Erroneous.
+    { T (S4), 2, { 1, LONG_MIN }, -1, true },
+    { T (S4), 2, { 1,  INT_MIN }, -1, true },
+    { T (S4), 2, { 1,    -4096 }, -1, true },
+    { T (S4), 2, { 1,    -1024 }, -1, true },
+    { T (S4), 2, { 1,       -1 }, -1, true },
+    { T (S4), 2, { 1,        0 }, -1, true },
+    { T (S4), 2, { 1,  INT_MAX }, -1, true },
+    { T (S4), 2, { 1, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { 0, LONG_MIN }, -1, true },
+    { T (S4), 2, { 0,  INT_MIN }, -1, true },
+    { T (S4), 2, { 0,    -4096 }, -1, true },
+    { T (S4), 2, { 0,    -1024 }, -1, true },
+    { T (S4), 2, { 0,       -1 }, -1, true },
+    { T (S4), 2, { 0,        0 }, -1, true },
+    { T (S4), 2, { 0,  INT_MAX }, -1, true },
+    { T (S4), 2, { 0, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { -1, LONG_MIN }, -1, true },
+    { T (S4), 2, { -1,  INT_MIN }, -1, true },
+    { T (S4), 2, { -1,    -4096 }, -1, true },
+    { T (S4), 2, { -1,    -1024 }, -1, true },
+    { T (S4), 2, { -1,       -1 }, -1, true },
+    { T (S4), 2, { -1,        0 }, -1, true },
+    { T (S4), 2, { -1,  INT_MAX }, -1, true },
+    { T (S4), 2, { -1, LONG_MAX }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, -1 }, -1, true },
+    { T (S4), 2, {  INT_MIN, -1 }, -1, true },
+    { T (S4), 2, {    -4096, -1 }, -1, true },
+    { T (S4), 2, {    -1024, -1 }, -1, true },
+    { T (S4), 2, {       -1, -1 }, -1, true },
+    { T (S4), 2, {        0, -1 }, -1, true },
+    { T (S4), 2, {  INT_MAX, -1 }, -1, true },
+    { T (S4), 2, { LONG_MAX, -1 }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, 0 }, -1, true },
+    { T (S4), 2, {  INT_MIN, 0 }, -1, true },
+    { T (S4), 2, {    -4096, 0 }, -1, true },
+    { T (S4), 2, {    -1024, 0 }, -1, true },
+    { T (S4), 2, {       -1, 0 }, -1, true },
+    { T (S4), 2, {        0, 0 }, -1, true },
+    { T (S4), 2, {  INT_MAX, 0 }, -1, true },
+    { T (S4), 2, { LONG_MAX, 0 }, -1, true },
+
+    { T (S4), 2, { LONG_MIN, LONG_MIN }, -1, true },
+    { T (S4), 2, {  INT_MIN,  INT_MIN }, -1, true },
+    { T (S4), 2, {    -4096     -4096 }, -1, true },
+    { T (S4), 2, {    -1024,    -1024 }, -1, true },
+    { T (S4), 2, {       -1,       -1 }, -1, true },
+    { T (S4), 2, {        0,        0 }, -1, true },
+    { T (S4), 2, {  INT_MAX,  INT_MAX }, -1, true },
+    { T (S4), 2, { LONG_MAX, LONG_MAX }, -1, true },
+
+    // Erroneous: excess initializers (and/or bad size).
+    { T (S4), 2, {        0,        0 },  0, true },
+    { T (S4), 2, {        0,        1 },  1, true },
+    { T (S4), 2, {        1,        0 },  2, true },
+    { T (S4), 2, {        1,        1 },  2, true },
+    { T (S4), 2, {        1,        1 },  2, true },
+    { T (S4), 2, {        1,        2 },  3, true },
+    { T (S4), 2, {        2,        1 },  3, true },
+
+    // Rank-3 VLAs with no initializers.
+    // Valid:
+    { T (S4), 3, {    1,    1,    1 }, -1, false },
+    { T (S4), 3, {    2,    2,    2 }, -1, false },
+    { T (S4), 3, {    3,    3,    3 }, -1, false },
+    { T (S4), 3, {    4,    4,    4 }, -1, false },
+    { T (S4), 3, {    5,    5,    5 }, -1, false },
+    { T (S4), 3, {    6,    6,    6 }, -1, false },
+    { T (S4), 3, {    7,    7,    7 }, -1, false },
+    { T (S4), 3, {    8,    8,    8 }, -1, false },
+
+    // Possibly erroneous:
+    { T (S4), 3, {    9,   16,   64 }, -1, -1 },
+
+    // Erroneous: bad size.
+    { T (S4), 3, {       -1,       -1,       -1 }, -1, true },
+    { T (S4), 3, {        0,       -1,       -1 }, -1, true },
+    { T (S4), 3, {       -1,        0,       -1 }, -1, true },
+    { T (S4), 3, {       -1,       -1,        0 }, -1, true },
+    { T (S4), 3, {        0,        0,        0 }, -1, true },
+    { T (S4), 3, {        1,        1,        0 }, -1, true },
+    { T (S4), 3, {        2,        0,        2 }, -1, true },
+    { T (S4), 3, {        0,        3,        3 }, -1, true },
+    { T (S4), 3, {        4,        4,       -1 }, -1, true },
+    { T (S4), 3, {        5,       -1,        5 }, -1, true },
+    { T (S4), 3, {       -1,        6,        6 }, -1, true },
+    { T (S4), 3, {        7,        7,  INT_MAX }, -1, true },
+    { T (S4), 3, {        8,  INT_MAX,        8 }, -1, true },
+    { T (S4), 3, {  INT_MAX,        9,        9 }, -1, true },
+    { T (S4), 3, {        0,        0,  INT_MIN }, -1, true },
+    { T (S4), 3, {        0,  INT_MIN,        0 }, -1, true },
+    { T (S4), 3, {  INT_MIN,        0,        0 }, -1, true },
+    { T (S4), 3, {  INT_MIN,  INT_MIN,  INT_MIN }, -1, true },
+    { T (S4), 3, {        0,        0,  INT_MAX }, -1, true },
+    { T (S4), 3, {        0,  INT_MAX,        0 }, -1, true },
+    { T (S4), 3, {  INT_MAX,        0,        0 }, -1, true },
+    { T (S4), 3, {        0,        0, LONG_MIN }, -1, true },
+    { T (S4), 3, {        0, LONG_MIN,        0 }, -1, true },
+    { T (S4), 3, { LONG_MIN,        0,        0 }, -1, true },
+    { T (S4), 3, { LONG_MIN, LONG_MIN, LONG_MIN }, -1, true },
+    { T (S4), 3, {        0,        0, LONG_MAX }, -1, true },
+    { T (S4), 3, {        0, LONG_MAX,        0 }, -1, true },
+    { T (S4), 3, { LONG_MAX,        0,        0 }, -1, true },
+
+    // Erroneous: integer overflow.
+    { T (S4), 3, {  INT_MAX,  INT_MAX,  INT_MAX }, -1, true },
+    { T (S4), 3, { LONG_MAX, LONG_MAX, LONG_MAX }, -1, true },
+    { T (S4), 3, {       10,       10, LONG_MAX }, -1, true },
+    { T (S4), 3, {       11, LONG_MAX,       11 }, -1, true },
+    { T (S4), 3, { LONG_MAX,       12,       12 }, -1, true },
+  };
+
+  static const size_t ntests = sizeof test / sizeof *test;
+
+  for (size_t i = 0; i != ntests; ++i)
+    {
+      // If test [i].except is negative, compute whether an exception
+      // should be expected based on the VLA rank and dimensions.
+      // Otherwise, use the hardcoded value.
+      bool vflow = ::vflow (test [i].size, test [i].rank, test [i].dims);
+      bool except = test [i].except < 0 ? vflow : test [i].except;
+
+      if (vflow && !except)
+        {
+          // When the VLA size computatiom overflows an exception
+          // must either be hardcoded as expected (true) or be left
+          // up to the computation.  Otherwise it's a consistency
+          // bug in the test case.
+          __builtin_printf ("line %i: test inconsistency\n", test [i].line);
+          __builtin_abort ();
+        }
+
+      try {
+        test [i].fun (test [i].rank, test [i].dims, test [i].init);
+        if (except)
+          __builtin_printf ("line %i: failed to throw\n",
+                            test [i].line);
+      }
+      catch (...) {
+        if (!except)
+          __builtin_printf ("line %i: unexpectedly threw\n",
+                            test [i].line);
+      }
+    }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla12.C b/gcc/testsuite/g++.dg/cpp1y/vla12.C
new file mode 100644
index 0000000..a8db578
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla12.C
@@ -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;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla13.C b/gcc/testsuite/g++.dg/cpp1y/vla13.C
new file mode 100644
index 0000000..7a7b423
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla13.C
@@ -0,0 +1,159 @@
+// PR c++/70019 - VLA size overflow not detected
+// Runtime test to verify that attempting to initialize a VLA with a string
+// longer than the number of elements causes an exception to be thrown.
+
+// { 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)
+
+// The size of the largest allowed VLA in bytes.  Bigger objects
+// cause an exception to be thrown.
+#define VLA_SIZE_MAX   0xffffU
+
+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;
+    }
+  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);
+
+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);
+
+// Helper macro to make it possible to pass as one multpile arguments
+// to another macro.
+#define Init(...) __VA_ARGS__
+
+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 comile-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);
+
+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..a2db08a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/vla14.C
@@ -0,0 +1,47 @@
+// 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 number of elements.
+
+// { 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..9b2d6b3
--- /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/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) {

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2016-04-15 14:33 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-07  1:38 [PATCH] 69517 - [5/6 regression] SEGV on a VLA with excess initializer elements Martin Sebor
2016-03-14 21:26 ` Martin Sebor
2016-03-21 22:10   ` PING #2 " Martin Sebor
2016-03-23 18:34 ` Jason Merrill
2016-03-23 22:50   ` Martin Sebor
2016-03-24 16:24     ` Jason Merrill
2016-04-01 23:02       ` Martin Sebor
2016-04-04 23:35         ` Jason Merrill
2016-04-08  0:05           ` Martin Sebor
2016-04-10 23:14             ` Martin Sebor
2016-04-12 15:43               ` Jason Merrill
2016-04-12 17:37                 ` Martin Sebor
2016-04-12 18:17               ` Jason Merrill
2016-04-13 18:37                 ` Martin Sebor
2016-04-13 19:26                   ` Jason Merrill
2016-04-14  2:35                   ` H.J. Lu
2016-04-14 15:32                     ` Martin Sebor
2016-04-14 10:40                   ` Andreas Schwab
2016-04-14 15:26                     ` Martin Sebor
2016-04-15  7:11                       ` Christophe Lyon
2016-04-15 12:31                       ` Jakub Jelinek
2016-04-15 14:33                         ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).