[PATCH] Fix ubsan's flexible array member handling (PR sanitizer/65280)

Marek Polacek polacek@redhat.com
Thu Mar 5 23:03:00 GMT 2015


ubsan's code to determine whether we're dealing with a flexible array member
didn't check for a COMPONENT_REF, but it should, since flexible array members
can only occur in a structure.  Consequently, we didn't instrument stuff we
should instrument.

Bootstrapped/regtested on x86_64-linux, if I hear no objections, I'll apply
this tomorrow.

2015-03-05  Marek Polacek  <polacek@redhat.com>
	    Martin Uecker  <uecker@eecs.berkeley.edu>

	PR sanitizer/65280
	* doc/invoke.texi: Update description of -fsanitize=bounds.

	* c-ubsan.c (ubsan_instrument_bounds): Check for COMPONENT_REF
	before trying to figure out whether we have a flexible array member.

	* c-c++-common/ubsan/bounds-1.c: Add testing of flexible array
	member-like arrays.
	* c-c++-common/ubsan/bounds-8.c: New test.
	* c-c++-common/ubsan/bounds-9.c: New test.
	* gcc.dg/ubsan/bounds-2.c: New test.

diff --git gcc/c-family/c-ubsan.c gcc/c-family/c-ubsan.c
index 90d59c0..a14426f 100644
--- gcc/c-family/c-ubsan.c
+++ gcc/c-family/c-ubsan.c
@@ -303,8 +303,9 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index,
 
   /* Detect flexible array members and suchlike.  */
   tree base = get_base_address (array);
-  if (base && (TREE_CODE (base) == INDIRECT_REF
-	       || TREE_CODE (base) == MEM_REF))
+  if (TREE_CODE (array) == COMPONENT_REF
+      && base && (TREE_CODE (base) == INDIRECT_REF
+		  || TREE_CODE (base) == MEM_REF))
     {
       tree next = NULL_TREE;
       tree cref = array;
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 006a852..67814d4 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -5704,8 +5704,8 @@ a++;
 @item -fsanitize=bounds
 @opindex fsanitize=bounds
 This option enables instrumentation of array bounds.  Various out of bounds
-accesses are detected.  Flexible array members and initializers of variables
-with static storage are not instrumented.
+accesses are detected.  Flexible array members, flexible array member-like
+arrays, and initializers of variables with static storage are not instrumented.
 
 @item -fsanitize=alignment
 @opindex fsanitize=alignment
diff --git gcc/testsuite/c-c++-common/ubsan/bounds-1.c gcc/testsuite/c-c++-common/ubsan/bounds-1.c
index 20e390f..5014f6f 100644
--- gcc/testsuite/c-c++-common/ubsan/bounds-1.c
+++ gcc/testsuite/c-c++-common/ubsan/bounds-1.c
@@ -6,6 +6,7 @@
 struct S { int a[10]; };
 struct T { int l; int a[]; };
 struct U { int l; int a[0]; };
+struct V { int l; int a[1]; };
 
 __attribute__ ((noinline, noclone))
 void
@@ -64,9 +65,14 @@ main (void)
   struct T *t = (struct T *) __builtin_malloc (sizeof (struct T) + 10);
   t->a[1] = 1;
 
+  /* Don't instrument zero-sized arrays (GNU extension).  */
   struct U *u = (struct U *) __builtin_malloc (sizeof (struct U) + 10);
   u->a[1] = 1;
 
+  /* Don't instrument last array in a struct.  */
+  struct V *v = (struct V *) __builtin_malloc (sizeof (struct V) + 10);
+  v->a[1] = 1;
+
   long int *d[10][5];
   d[9][0] = (long int *) 0;
   d[8][3] = d[9][0];
diff --git gcc/testsuite/c-c++-common/ubsan/bounds-8.c gcc/testsuite/c-c++-common/ubsan/bounds-8.c
index e69de29..a43b480 100644
--- gcc/testsuite/c-c++-common/ubsan/bounds-8.c
+++ gcc/testsuite/c-c++-common/ubsan/bounds-8.c
@@ -0,0 +1,13 @@
+/* PR sanitizer/65280 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+
+int
+main (void)
+{
+  int *t = (int *) __builtin_malloc (sizeof (int) * 10);
+  int (*a)[1] = (int (*)[1]) t;
+  (*a)[2] = 1;
+}
+
+/* { dg-output "index 2 out of bounds for type 'int \\\[1\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
diff --git gcc/testsuite/c-c++-common/ubsan/bounds-9.c gcc/testsuite/c-c++-common/ubsan/bounds-9.c
index e69de29..61c11f4 100644
--- gcc/testsuite/c-c++-common/ubsan/bounds-9.c
+++ gcc/testsuite/c-c++-common/ubsan/bounds-9.c
@@ -0,0 +1,24 @@
+/* PR sanitizer/65280 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* Origin: Martin Uecker <uecker@eecs.berkeley.edu> */
+
+void
+foo (volatile int (*a)[3])
+{
+  (*a)[3] = 1;	// error
+  a[0][0] = 1;	// ok
+  a[1][0] = 1;	// ok
+  a[1][4] = 1;	// error
+}
+
+int
+main ()
+{
+  volatile int a[20];
+  foo ((int (*)[3]) &a);
+  return 0;
+}
+
+/* { dg-output "index 3 out of bounds for type 'int \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 4 out of bounds for type 'int \\\[3\\\]'" } */
diff --git gcc/testsuite/gcc.dg/ubsan/bounds-2.c gcc/testsuite/gcc.dg/ubsan/bounds-2.c
index e69de29..3e88035 100644
--- gcc/testsuite/gcc.dg/ubsan/bounds-2.c
+++ gcc/testsuite/gcc.dg/ubsan/bounds-2.c
@@ -0,0 +1,18 @@
+/* PR sanitizer/65280 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+
+void
+foo (int n, int (*b)[n])
+{
+  (*b)[n] = 1;
+}
+
+int
+main ()
+{
+  int a[20];
+  foo (3, (int (*)[3]) &a);
+}
+
+/* { dg-output "index 3 out of bounds for type 'int \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */

	Marek



More information about the Gcc-patches mailing list