[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