Hi,

This is the 8th version of the patch set to extend "counted_by" attribute
 to pointer fields of structures, which fixes PR120929:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120929

The 8th version of the patch has the following difference compared to the 7th
version:

1. Add the fix for PR120929 in gcc/tree-object-size.cc, and testing case for
   PR120929 gcc.dg/pr120929.c (in Patch 2);
   based on Sid's patch for P120929. 
    https://gcc.gnu.org/pipermail/gcc-patches/2025-July/688588.html
2. Add one more testing case gcc.dg/pointer-counted-by-8.c to check the code
   generation of pointers with counted_by attribute (in Patch 1);
3. Handle error_mark_node returned by build_counted_by_ref. Impacted routines
   include (in Patch 1):
        * c-parser.cc (c_parser_postfix_expression): Handle returned
        error_mark_node from handle_counted_by_for_component_ref.
        * c-typeck.cc (build_counted_by_ref): Return error_mark_node when
        issue error.
        (handle_counted_by_for_component_ref): Handle returned
        error_mark_node from build_counted_by_ref.
        (build_component_ref): Handle returned error_mark_node from
        handle_counted_by_for_component_ref.

The whole patch set has been bootstrapped and regression tested on both aarch64 
and x86.

Okay for trunk?

Thanks.

Qing

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

The 7th version of the patch has been committed into trunk, but triggered
PR120929. I reverted the patches from trunk due to PR120929.  

In order to fix PR120929, we agreed on the following solution:

Instead of passing the ADDRESS of the original pointer as the first argument
to the call to .ACCESS_WITH_SIZE, we should pass the VALUE of the original
pointer. The same for the returned value from the call to .ACCESS_WITH_SIZE.

However, this design of the .ACCESS_WITH_SIZE for pointers with counted_by
turns out to have an fundamental issue as explained below.

For a pointer field with counted_by attribute:

struct S {
  int n;
  int *p __attribute__((counted_by(n)));
} *f;

f->p = malloc (size); 

there are two approaches to generate the call to .ACCESS_WITH_SIZE for f->p.

A. Pass the ADDRESS of the original pointer &(f->p) as the first argument,
   and also return the ADDRESS of the original pointer:
 *.ACCESS_WITH_SIZE (&f->p, &f->n,...)

B. Pass the VALUE of the original pointer f->p as the first argument,
   and also return the original pointer:
 .ACCESS_WITH_SIZE (f->p, &f->n,...)

The approach A was used in the previous committed (and reverted) patch;
The approach B was suggested and agreed to fix PR120929 based on our previous
discussion on PR120929. 

After study, the approach B is confirmed to bring undefined behavior into
the application.

f->p = malloc (size); 

***** With the approach B: the IL for the above is:
 
  tmp1 = f->p;
  tmp2 = &f->n;
  tmp3 = .ACCESS_WITH_SIZE (tmp1, tmp2, ...);
  tmp4 = malloc (size);
  tmp3 = tmp4;

In the above, in order to generate a call to .ACCESS_WITH_SIZE for the pointer
reference f->p,  the new GIMPLE tmp1 = f->p is necessary to pass the value of
the pointer f->p to the call to .ACCESS_WITH_SIZE. However, this new GIMPLE is
the one that brings UB into the application since the value of f->p is not 
initialized yet when it is assigned to "tmp1".

the above IL will be expanded to the following when .ACCESS_WITH_SIZE is 
expanded
to its first argument:

  tmp1 = f->p;
  tmp2 = &f->n;
  tmp3 = tmp1;
  tmp4 = malloc (size);
  tmp3 = tmp4;

the final optimized IL will be: 

  tmp3 = f->p;
  tmp3 = malloc (size);;

As a result, the f->p will NOT be set correctly to the pointer
returned by malloc (size).

***** With the Approach A, the IL is:

  tmp1 = &f->p;
  tmp2 = &f->n;
  tmp3 = .ACCESS_WITH_SIZE (tmp1, tmp2, ...);
  tmp4 = malloc (size);
  *tmp3 = tmp4;
 
After .ACCESS_WITH_SIZE is expanded to its first argument:

  tmp1 = &f->p;
  tmp2 = &f->n;
  tmp3 = tmp1;
  tmp4 = malloc (size);
  *tmp3 = tmp4;

The final optimized IL will be:

  *(&f->p) = malloc (size);

Which is the correct IL for the original source code.

Based on the above, We should take the Approach A for the pointers with
counted_by attribute. i.e:

A. Pass the ADDRESS of the original pointer &(f->p) as the first argument,
   and also return the ADDRESS of the original pointer:
 *.ACCESS_WITH_SIZE (&f->p, &f->n,...)

Reply via email to