This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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 <jason@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				(vec<tree, va_gc> **, tree, tree,
 						 vec<tree, 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
 @item -fsanitize=vla-bound
 @opindex fsanitize=vla-bound
 This option instructs the compiler to check that the size of a variable
-length array is positive.  This option does not have any effect in
-@option{-std=c++14} mode, as the standard requires the exception be thrown
-instead.
+length array is positive.
 
 @item -fsanitize=null
 @opindex fsanitize=null
diff --git a/gcc/testsuite/g++.dg/ubsan/vla-1.C b/gcc/testsuite/g++.dg/ubsan/vla-1.C
new file mode 100644
index 0000000..e7f2494
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/vla-1.C
@@ -0,0 +1,13 @@
+// { dg-do run }
+// { dg-options "-Wno-vla -fsanitize=undefined" }
+// { dg-shouldfail "ubsan" }
+// { dg-output "index 1 out of bounds" }
+
+void f(int i) {
+  int ar[i] = { 42, 24 };
+}
+
+int main()
+{
+  f(1);
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]