For a pointer array reference that is annotated with counted_by attribute,
such as:

  struct annotated {
    int *c __attribute__ ((counted_by (b)));
    int b;
  };

  struct annotated *p = setup (10);
  p->c[12] = 2; //out of bound access

the IR for p->c[12] is:
  (.ACCESS_WITH_SIZE (p->c, &p->b, 0B, 4) + 48) = 2;

The current routine get_index_from_offset in c-family/c-ubsan.cc cannot
handle the integer constant offset "48" correctly.

The fix is to enhance "get_index_from_offset" to correctly handle the constant
offset.

bootstrapped and regression tested on both x86 and aarch64. no issues.

okay for committing?

thanks.

Qing

===================

        PR c/124230

gcc/c-family/ChangeLog:

        * c-ubsan.cc (get_index_from_offset): Handle the special case when
        the offset is an integer constant.

gcc/testsuite/ChangeLog:

        * gcc.dg/ubsan/pointer-counted-by-bounds-124230-char.c: New test.
        * gcc.dg/ubsan/pointer-counted-by-bounds-124230-float.c: New test.
        * gcc.dg/ubsan/pointer-counted-by-bounds-124230-struct.c: New test.
        * gcc.dg/ubsan/pointer-counted-by-bounds-124230-union.c: New test.
        * gcc.dg/ubsan/pointer-counted-by-bounds-124230.c: New test.
---
 gcc/c-family/c-ubsan.cc                       | 15 ++++-
 .../pointer-counted-by-bounds-124230-char.c   |  9 +++
 .../pointer-counted-by-bounds-124230-float.c  |  9 +++
 .../pointer-counted-by-bounds-124230-struct.c | 61 +++++++++++++++++++
 .../pointer-counted-by-bounds-124230-union.c  | 61 +++++++++++++++++++
 .../ubsan/pointer-counted-by-bounds-124230.c  | 59 ++++++++++++++++++
 6 files changed, 213 insertions(+), 1 deletion(-)
 create mode 100644 
gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-char.c
 create mode 100644 
gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-float.c
 create mode 100644 
gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-struct.c
 create mode 100644 
gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-union.c
 create mode 100644 
gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230.c

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index 155af5e952c..513ede28c03 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -659,6 +659,9 @@ get_factors_from_mul_expr (tree mult_expr, tree parent,
    ELEMENT_SIZE:
     (sizetype) SAVE_EXPR <n> * 4
    get the index as (long unsigned int) m, and return it.
+   One special case is when the OFFSET is an integer constant, and the
+   element_size is also an interger constant, we should get the index
+   as OFFSET/element_size.
    The INDEX_P holds the pointer to the parent tree of the index,
    INDEX_N holds the position of the index in its parent.  */
 
@@ -666,9 +669,19 @@ static tree
 get_index_from_offset (tree offset, tree *index_p,
                       int *index_n, tree element_size)
 {
-  if (TREE_CODE (offset) != MULT_EXPR)
+  if (TREE_CODE (offset) != MULT_EXPR
+      && TREE_CODE (offset) != INTEGER_CST)
     return NULL_TREE;
 
+  if (TREE_CODE (offset) == INTEGER_CST
+      && TREE_CODE (element_size) != INTEGER_CST)
+    return NULL_TREE;
+
+  if (TREE_CODE (offset) == INTEGER_CST
+      && TREE_CODE (element_size) == INTEGER_CST)
+    return fold_build2 (EXACT_DIV_EXPR, TREE_TYPE (offset),
+                       offset, element_size);
+
   auto_vec<factor_t> e_factors, o_factors;
   get_factors_from_mul_expr (element_size, NULL, -1, &e_factors);
   get_factors_from_mul_expr (offset, *index_p, *index_n, &o_factors);
diff --git a/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-char.c 
b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-char.c
new file mode 100644
index 00000000000..b58bfa2c58b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-char.c
@@ -0,0 +1,9 @@
+/* Test the attribute counted_by for pointer fields and its usage in
+   bounds sanitizer.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* { dg-output "index 10 out of bounds for type 'char 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'char 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+#define PTR_TYPE char
+#include "pointer-counted-by-bounds-124230.c"
diff --git 
a/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-float.c 
b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-float.c
new file mode 100644
index 00000000000..6bf686fe6ea
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-float.c
@@ -0,0 +1,9 @@
+/* Test the attribute counted_by for pointer fields and its usage in
+   bounds sanitizer.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* { dg-output "index 10 out of bounds for type 'float 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'float 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+#define PTR_TYPE float 
+#include "pointer-counted-by-bounds-124230.c"
diff --git 
a/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-struct.c 
b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-struct.c
new file mode 100644
index 00000000000..41b0b7d3d28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-struct.c
@@ -0,0 +1,61 @@
+/* Test the attribute counted_by for pointer fields and its usage in
+   bounds sanitizer.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* { dg-output "index 10 out of bounds for type 'A 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'A 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+#include <stdlib.h>
+
+struct A {
+  int a;
+  char *b;
+};
+#define PTR_TYPE struct A 
+struct annotated {
+  int b;
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+} *p_array_annotated;
+
+struct nested_annotated {
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+  struct {
+    union {
+      int b;
+      float f;
+    };
+    int n;
+  };
+} *p_array_nested_annotated;
+
+void __attribute__((__noinline__)) setup (int annotated_count)
+{
+  p_array_annotated
+    = (struct annotated *) malloc (sizeof (struct annotated));
+  p_array_annotated->c = (PTR_TYPE *) malloc (annotated_count * sizeof 
(PTR_TYPE));
+  p_array_annotated->b = annotated_count;
+
+  p_array_nested_annotated
+    = (struct nested_annotated *) malloc (sizeof (struct nested_annotated));
+  p_array_nested_annotated->c = (PTR_TYPE *) malloc (sizeof (PTR_TYPE) * 
annotated_count);
+  p_array_nested_annotated->b = annotated_count;
+
+  return;
+}
+
+void cleanup ()
+{
+  free (p_array_annotated->c);
+  free (p_array_annotated);
+  free (p_array_nested_annotated->c);
+  free (p_array_nested_annotated);
+}
+
+int main(int argc, char *argv[])
+{
+  setup (10);   
+  p_array_annotated->c[10].a = 2;
+  p_array_nested_annotated->c[11].a = 3;
+  cleanup ();
+  return 0;
+}
diff --git 
a/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-union.c 
b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-union.c
new file mode 100644
index 00000000000..7157c98d782
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230-union.c
@@ -0,0 +1,61 @@
+/* Test the attribute counted_by for pointer fields and its usage in
+   bounds sanitizer.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* { dg-output "index 10 out of bounds for type 'A 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'A 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+#include <stdlib.h>
+
+union A {
+  int a;
+  float b;
+};
+#define PTR_TYPE union A 
+struct annotated {
+  int b;
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+} *p_array_annotated;
+
+struct nested_annotated {
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+  struct {
+    union {
+      int b;
+      float f;
+    };
+    int n;
+  };
+} *p_array_nested_annotated;
+
+void __attribute__((__noinline__)) setup (int annotated_count)
+{
+  p_array_annotated
+    = (struct annotated *) malloc (sizeof (struct annotated));
+  p_array_annotated->c = (PTR_TYPE *) malloc (annotated_count * sizeof 
(PTR_TYPE));
+  p_array_annotated->b = annotated_count;
+
+  p_array_nested_annotated
+    = (struct nested_annotated *) malloc (sizeof (struct nested_annotated));
+  p_array_nested_annotated->c = (PTR_TYPE *) malloc (sizeof (PTR_TYPE) * 
annotated_count);
+  p_array_nested_annotated->b = annotated_count;
+
+  return;
+}
+
+void cleanup ()
+{
+  free (p_array_annotated->c);
+  free (p_array_annotated);
+  free (p_array_nested_annotated->c);
+  free (p_array_nested_annotated);
+}
+
+int main(int argc, char *argv[])
+{
+  setup (10);   
+  p_array_annotated->c[10].a = 2;
+  p_array_nested_annotated->c[11].a = 3;
+  cleanup ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230.c 
b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230.c
new file mode 100644
index 00000000000..26aef7f1f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pointer-counted-by-bounds-124230.c
@@ -0,0 +1,59 @@
+/* Test the attribute counted_by for pointer fields and its usage in
+   bounds sanitizer.  */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=bounds" } */
+/* { dg-output "index 10 out of bounds for type 'int 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'int 
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+
+#include <stdlib.h>
+
+#ifndef PTR_TYPE
+#define PTR_TYPE int
+#endif
+struct annotated {
+  int b;
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+} *p_array_annotated;
+
+struct nested_annotated {
+  PTR_TYPE *c __attribute__ ((counted_by (b)));
+  struct {
+    union {
+      int b;
+      float f;
+    };
+    int n;
+  };
+} *p_array_nested_annotated;
+
+void __attribute__((__noinline__)) setup (int annotated_count)
+{
+  p_array_annotated
+    = (struct annotated *) malloc (sizeof (struct annotated));
+  p_array_annotated->c = (PTR_TYPE *) malloc (annotated_count * sizeof 
(PTR_TYPE));
+  p_array_annotated->b = annotated_count;
+
+  p_array_nested_annotated
+    = (struct nested_annotated *) malloc (sizeof (struct nested_annotated));
+  p_array_nested_annotated->c = (PTR_TYPE *) malloc (sizeof (PTR_TYPE) * 
annotated_count);
+  p_array_nested_annotated->b = annotated_count;
+
+  return;
+}
+
+void cleanup ()
+{
+  free (p_array_annotated->c);
+  free (p_array_annotated);
+  free (p_array_nested_annotated->c);
+  free (p_array_nested_annotated);
+}
+
+int main(int argc, char *argv[])
+{
+  setup (10);   
+  p_array_annotated->c[10] = 2;
+  p_array_nested_annotated->c[11] = 3;
+  cleanup ();
+  return 0;
+}
-- 
2.43.5

Reply via email to