On Mon, Jul 14, 2025 at 10:58 PM Qing Zhao <qing.z...@oracle.com> wrote:
>
>
> > On Jul 7, 2025, at 13:07, Qing Zhao <qing.z...@oracle.com> wrote:
> >
> > As I mentioned in the latest email I replied to the thread, the original 
> > implementation of the counted_by for pointer was implemented without the 
> > additional indirection.
> > But that implementation has a fundamental bug during testing.  then I 
> > changed the implementation like the current.
> >
> > I need spending a little more time to find the details of that fundamental 
> > bug with the original implementation.
> >
> > If the current bug is urgent to be fixed. and you are not comfortable with 
> > the simple Patch Sid provided, then I am okay to back it out now and then 
> > push it back with the fix to this current bug at a later time after 
> > everyone is comfortable with the current implementation.
> >
> > Thanks a lot!
> >
> > Qing
>
>
> Hi,  this is an update on the above fundamental issue I mentioned previously. 
> (I finally located this issue and recorded it here)
>
> 1. Based on the previous discussion on how to resolve PR120929, we agreed the 
> following solution:
>
> struct S {
>   int n;
>   int *p __attribute__((counted_by(n)));
> } *f;
>
> when generating a call to .ACCESS_WITH_SIZE for f->p, instead of generating
>  *.ACCESS_WITH_SIZE (&f->p, &f->n,...)
>
> We should generate
>  .ACCESS_WITH_SIZE (f->p, &f->n,...)
>
> i.e.,
> the return type and the type of the first argument of the call is the
>    original pointer type in this version,
>    instead of the pointer to the original pointer type in the 7th version;
>
> 2. I implemented this new .ACCESS_WITH_SIZE generation for pointers in my 
> local workspace. It looked fine in the beginning,
> However, during testing, I finally located the _fundamental issue_ with this 
> design.
>
> This issue can be shown clearly with the following simple testing case:
> (Note, the numbers on the left in the following testing case is the line #)
>
> $ cat t1.c
>   1 struct annotated {
>   2   int b;
>   3   int *c __attribute__ ((counted_by (b)));
>   4 } *p_array_annotated;
>   5
>   6 void __attribute__((__noinline__)) setup (int annotated_count)
>   7 {
>   8   p_array_annotated
>   9     = (struct annotated *) __builtin_malloc (sizeof (struct annotated));
>  10   p_array_annotated->c = (int *) __builtin_malloc (annotated_count * 
> sizeof (int));
>  11   p_array_annotated->c[2] = 10;
>  12   p_array_annotated->b = annotated_count;

But isn't this bogus since you access c[2] while it's counted_by value
is still uninitialized?
I'd say by using counted_by you now invoke UB here.

Richard.

>  13   return;
>  14 }
>  15
>  16 int main(int argc, char *argv[])
>  17 {
>  18   setup (10);
>  19   return 0;
>  20 }
>
> $my-gcc t1.c    -O0 -g  -o ./t1.exe -fdump-tree-gimple
> $ ./t1.exe
> Segmentation fault (core dumped)
>
> 3. As I debugged, the segmentation fault happened at line 11: 
> p_array_annotated->c[2] = 10;
>     Since the value of the pointer "p_array_annotated->c” is  0x0.
>
> 4. Study the gimple dump t1.c.007t.gimple as following:
>
>   1 __attribute__((noinline))
>   2 void setup (int annotated_count)
>   3 {
>   4   int * D.2969;
>   5    6   _1 = __builtin_malloc (16);
>   7   p_array_annotated = _1;
>   8   _2 = (long unsigned int) annotated_count;
>   9   _3 = _2 * 4;
>  10   p_array_annotated.0_4 = p_array_annotated;
>  11   _5 = p_array_annotated.0_4->c;
>  12   p_array_annotated.1_6 = p_array_annotated;
>  13   _7 = &p_array_annotated.1_6->b;
>  14   D.2969 = .ACCESS_WITH_SIZE (_5, _7, 0B, 4);
>  15   _8 = __builtin_malloc (_3);
>  16   D.2969 = _8;
>  17   p_array_annotated.2_10 = p_array_annotated;
>  18   _11 = p_array_annotated.2_10->c;
>  19   p_array_annotated.3_12 = p_array_annotated;
>  20   _13 = &p_array_annotated.3_12->b;
>  21   _9 = .ACCESS_WITH_SIZE (_11, _13, 0B, 4);
>  22   _14 = _9 + 8;
>  23   *_14 = 10;
>  24   p_array_annotated.4_15 = p_array_annotated;
>  25   p_array_annotated.4_15->b = annotated_count;
>  26   return;
>  27 }
>
> We can see the root cause of this problem is because we passed the _value_ of 
>  “p_array_annotated->c”
> instead of the _address_ of “p_array_annotated->c” to .ACCESS_WITH_SIZE:
>
> At line 11, the value of “p_array_annotated.0_4->c” is 0x0 when it was 
> assigned to “_5”;
> At line 14, the value of “_5” is passed to the call to .ACCESS_WITH_SIZE, 
> which also is 0x0;
>
> And later when we expand .ACCESS_WITH_SIZE (_5, _7, 0B, 4), we replace it 
> with its first argument “_5”,
> As a result, the IL after the expand will look like the following:
>
> 11       _5 = p_array_annotated.0_4->c;
> 14      D.2969 = _5;
> 15      _8 = __builtin_malloc (_3);
> 16      D.2969 = _8:
>
> We can clearly see that the above IL is wrong: p_array_annotated->c is 
> initialized as 0x0, and this value is passed
> to the pointer D.2969, which is 0x0 too.
>
> 5.  This is exactly the fundamental issue I met in the very beginning during 
> my implementation of the counted_by for
> pointers. I should record this issue at that time and sent email to the alias 
> at that time.
>
> 6.  Based on this issue, I changed the .ACCESS_WITH_SIZE for pointers to
>
>  *.ACCESS_WITH_SIZE (&f->p, &f->n,…)
>
> at that time.
>
> And this resolved this fundamental issue.
>
> In a summary:
>
> 1. We still need to keep the design of  .ACCESS_WITH_SIZE for pointers  as in 
> patch version #7, i.e:
>
> *.ACCESS_WITH_SIZE (&f->p, &f->n,…)
>
> 2. As a side effect of the above IL , the change in gcc/tree-object-size.cc 
> <http://tree-object-size.cc/> in patch version #7 is still needed:
>
> @@ -1854,6 +1856,17 @@ collect_object_sizes_for (struct object_size_info 
> *osi, tree var)
>              if (TREE_CODE (rhs) == SSA_NAME
>                  && POINTER_TYPE_P (TREE_TYPE (rhs)))
>               reexamine = merge_object_sizes (osi, var, rhs);
> +           /* Handle the following stmt #2 to propagate the size from the
> +              stmt #1 to #3:
> +               1  _1 = .ACCESS_WITH_SIZE (_3, _4, 1, 0, -1, 0B);
> +               2  _5 = *_1;
> +               3  _6 = __builtin_dynamic_object_size (_5, 1);
> +            */
> +           else if (TREE_CODE (rhs) == MEM_REF
> +                    && POINTER_TYPE_P (TREE_TYPE (rhs))
> +                    && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
> +                    && integer_zerop (TREE_OPERAND (rhs, 1)))
> +             reexamine = merge_object_sizes (osi, var, TREE_OPERAND (rhs, 
> 0));
>
> But, we should add one more condition to the above in order to limit such 
> propagation ONLY to
> the pointee is .ACCESS_WITH_SIZE, i.e (as Sid proposed)
>
> +/* Return true if PTR is defined with .ACCESS_WITH_SIZE.  */
> +
> +static bool
> +is_access_with_size (tree ptr)
> +{
> +  gcc_assert (TREE_CODE (ptr) == SSA_NAME);
> +
> +  gimple *stmt = SSA_NAME_DEF_STMT (ptr);
> +  if (gimple_code (stmt) != GIMPLE_CALL)
> +    return false;
> +
> +  return gimple_call_internal_p (as_a <gcall *> (stmt), 
> IFN_ACCESS_WITH_SIZE);
> +}
> +
>
>
> +           /* Handle the following stmt #2 to propagate the size from the
> +              stmt #1 to #3:
> +               1  _1 = .ACCESS_WITH_SIZE (_3, _4, 1, 0, -1, 0B);
> +               2  _5 = *_1;
> +               3  _6 = __builtin_dynamic_object_size (_5, 1);
> +            */
> +           else if (TREE_CODE (rhs) == MEM_REF
> +                    && POINTER_TYPE_P (TREE_TYPE (rhs))
> +                    && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
> +                    && integer_zerop (TREE_OPERAND (rhs, 1))
> +                     && is_access_with_size (TREE_OPERAND (rhs, 0)))
> +             reexamine = merge_object_sizes (osi, var, TREE_OPERAND (rhs, 
> 0));
>
> Let me know if you have comments or suggestions to this fundamental issue and 
> whether my
> solution to it was reasonable.
>
> Thanks a lot.
>
> Qing
>
>
>

Reply via email to