Re: RFC: C++ PATCH to do bounds sanitation for VLA initialization

2015-01-08 Thread Marek Polacek
On Wed, Jan 07, 2015 at 11:56:58PM -0500, Jason Merrill wrote:
 My recent patch to remove the C++ VLA semantics that didn't make it into
 C++14 missed a couple of spots.  While I was looking at that I noticed that
 we weren't sanitizing VLA initialization, which we ought to do; this patch
 implements that.  Marek, does my choice of VLA|BOUNDS make sense to you?

I think that should be just BOUNDS.  VLA sanitization will still catch
the case if the size of a VLA is not positive, e.g.
  int i = -1;
  int a[i] = { 1, 2, 3};

Marek


RFC: C++ PATCH to do bounds sanitation for VLA initialization

2015-01-07 Thread Jason Merrill
My recent patch to remove the C++ VLA semantics that didn't make it into 
C++14 missed a couple of spots.  While I was looking at that I noticed 
that we weren't sanitizing VLA initialization, which we ought to do; 
this patch implements that.  Marek, does my choice of VLA|BOUNDS make 
sense to you?


Tested x86_64-pc-linux-gnu.
commit 0beea6f184261c0948894ee54af27cd58ce452aa
Author: Jason Merrill ja...@redhat.com
Date:   Wed Jan 7 17:10:18 2015 -0500

	* init.c (build_vec_init): Call ubsan_instrument_bounds to check
	whether an initializer-list is too big for a VLA.
	(throw_bad_array_length): Remove.
	* cp-tree.h: Remove prototype.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2afa531..77f2b5b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5574,7 +5574,6 @@ extern tree get_nsdmi(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 		 tsubst_flags_t);
 extern tree throw_bad_array_new_length		(void);
-extern tree throw_bad_array_length		(void);
 extern tree build_new(vectree, va_gc **, tree, tree,
 		 vectree, va_gc **, int,
  tsubst_flags_t);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index a5ac11c..ebc09a5 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include target.h
 #include gimplify.h
 #include wide-int.h
+#include c-family/c-ubsan.h
 
 static bool begin_init_stmts (tree *, tree *);
 static tree finish_init_stmts (bool, tree, tree);
@@ -2241,20 +2242,6 @@ throw_bad_array_new_length (void)
   return build_cxx_call (fn, 0, NULL, tf_warning_or_error);
 }
 
-/* Call __cxa_bad_array_length to indicate that there were too many
-   initializers.  */
-
-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);
-}
-
 /* Generate code for a new-expression, including calling the operator
new function, initializing the object, and, if an exception occurs
during construction, cleaning up.  The arguments are as for
@@ -3419,7 +3406,6 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree obase = base;
   bool xvalue = false;
   bool errors = false;
-  tree length_check = NULL_TREE;
 
   if (TREE_CODE (atype) == ARRAY_TYPE  TYPE_DOMAIN (atype))
 maxindex = array_type_nelts (atype);
@@ -3440,12 +3426,9 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   /* If we have a braced-init-list, make sure that the array
  is big enough for all the initializers.  */
-  if (init  TREE_CODE (init) == CONSTRUCTOR
-   CONSTRUCTOR_NELTS (init)  0
-   !TREE_CONSTANT (maxindex)
-   flag_exceptions)
-length_check = fold_build2 (LT_EXPR, boolean_type_node, maxindex,
-size_int (CONSTRUCTOR_NELTS (init) - 1));
+  bool length_check = (init  TREE_CODE (init) == CONSTRUCTOR
+		CONSTRUCTOR_NELTS (init)  0
+		!TREE_CONSTANT (maxindex));
 
   if (init
TREE_CODE (atype) == ARRAY_TYPE
@@ -3468,10 +3451,6 @@ build_vec_init (tree base, tree maxindex, tree init,
   if (BRACE_ENCLOSED_INITIALIZER_P (init))
 	init = digest_init (atype, init, complain);
   stmt_expr = build2 (INIT_EXPR, atype, base, init);
-  if (length_check)
-	stmt_expr = build3 (COND_EXPR, atype, length_check,
-			throw_bad_array_length (),
-			stmt_expr);
   return stmt_expr;
 }
 
@@ -3582,11 +3561,30 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   if (length_check)
 	{
-	  tree throw_call;
-	  throw_call = throw_bad_array_new_length ();
-	  length_check = build3 (COND_EXPR, void_type_node, length_check,
- throw_call, void_node);
-	  finish_expr_stmt (length_check);
+	  tree nelts = size_int (CONSTRUCTOR_NELTS (init) - 1);
+	  if (TREE_CODE (atype) != ARRAY_TYPE)
+	{
+	  if (flag_exceptions)
+		{
+		  tree c = fold_build2 (LT_EXPR, boolean_type_node, iterator,
+	nelts);
+		  c = build3 (COND_EXPR, void_type_node, c,
+			  throw_bad_array_new_length (), void_node);
+		  finish_expr_stmt (c);
+		}
+	  /* Don't check an array new when -fno-exceptions.  */
+	}
+	  else if (flag_sanitize  (SANITIZE_VLA | SANITIZE_BOUNDS)
+		current_function_decl
+		!lookup_attribute (no_sanitize_undefined,
+	 DECL_ATTRIBUTES
+	 (current_function_decl)))
+	{
+	  /* Make sure the last element of the initializer is in bounds. */
+	  finish_expr_stmt
+		(ubsan_instrument_bounds
+		 (input_location, obase, nelts, /*ignore_off_by_one*/false));
+	}
 	}
 
   if (try_const)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c30efe3..1141c5b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5628,9 +5628,7 @@ call into a diagnostics message call instead.  When reaching the