Ping! Thanks.
Qing > On Feb 25, 2026, at 11:00, Qing Zhao <[email protected]> wrote: > > 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 >
