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
> 

Reply via email to