Am Donnerstag, dem 05.12.2024 um 21:09 +0000 schrieb Qing Zhao:
>
> > On Dec 3, 2024, at 10:29, Qing Zhao <[email protected]> wrote:
....
> > >
> > > > >
> > > > > > >
> > > > > > > It would be clearer if you the syntax ".n" which resembles
> > > > > > > the syntax for designated initializers that is already used
> > > > > > > in initializers to refer to struct members.
> > > > > > >
> > > > > > > constexpr int n;
> > > > > > > struct foo {
> > > > > > > {
> > > > > > > char (*p)[n] __attribute__ ((counted_by (.n))
> > > > > > > int n;
> > > > > > > }
> > > > > > >
> > > > > > Yes, I agree.
> > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > > > >
> > > > > > > > > > There is one important additional requirement:
> > > > > > > > > >
> > > > > > > > > > x->n, x->p can ONLY be changed by changing the whole
> > > > > > > > > > structure at the same time.
> > > > > > > > > > Otherwise, x->n might not be consistent with x->p.
> > > > > > > > >
> > > > > > > > > By itself, this would still not fix the issue I pointed out.
> > > > > > > > >
> > > > > > > > > struct foo x;
> > > > > > > > > x = .. ; // set the whole structure
> > > > > > > > > char *p = x->p;
> > > > > > > > > x = ... ; // set the whole structure
> > > > > > > > >
> > > > > > > > > What is the bound for 'p' ?
> > > > > > > >
> > > > > > > > Since p was set to the pointer field of the old structure, then
> > > > > > > > the bound of it should be the old bound.
> > > > > > > > > With current rules it would be the old bound.
> > > > > > > >
> > > > > > > > I thought that this should be the correct behavior, isn’t it?
> > > > > > >
> > > > > > > Yes, sorry, what I meant was "with the current rules it would be
> > > > > > > the *new* bound”.
> > > > > >
> > > > > > struct foo x;
> > > > > > x=… ; // set the whole structure 1
> > > > > > char *p = x->p;
> > > > > > x=… ; // set the whole structure 2
> > > > > >
> > > > > > In the above, when “set the whole structure 1”, x1, x1->n and x1->p
> > > > > > are set at the same time;
> > > > > > After *p = x->p; the pointer “p” is pointing to “x1->p”, it’s
> > > > > > bound is “x1->n”;
> > > > >
> > > > > I agree.
> > > > > >
> > > > > > Then when “set the whole structure 2”, x2 is different than x1,
> > > > > > x2->n and x2->p are set at the same time, the pointer
> > > > > > ‘p’ still points to “x1->p”, therefore it’s bound should be
> > > > > > “x1->n”.
> > > > > >
> > > > > > So, as long as the whole structure is set at the same time, should
> > > > > > be fine.
> > > > > >
> > > > > > Do I miss anything here?
> > > > >
> > > > > I was talking aout the pointer "p" which was obtained before setting
> > > > > the
> > > > > struct the second time in
> > > > >
> > > > > char *p = x->p;
> > > > >
> > > > > This pointer is still set to x1->p but the bound refers to x.n which
> > > > > is
> > > > > now set to x2->n.
> > > >
> > > > You mean:
> > > >
> > > > struct foo x;
> > > > x=… ; // set the whole structure 1
> > > > char *p = x->p;
> > > > x=… ; // set the whole structure 2
> > > > p[index] = 10; // at this point, p’s bound is x2->n, not x1->n?
> > > >
> > > > Yes, you are right here.
> > > >
> > > > So, is there similar problem with the corresponding language extension?
> > > >
> > >
> > > The language extension does not exist yet, so there is no problem.
> > Yeah, I should mention this as “corresponding future language extension” -:)
> > >
> > > But I hope we will get it and then specify it so that this works
> > > correctly without this footgun.
> > >
> > > Of course, if GCC gets the "counted_by" attribute wrong, there will
> > > be arguments later in WG14 why the feature is then different to it.
> >
> > I think that we need to resolve this issue first in the design of
> > “counted_by” for pointer fields.
> > I guess that we might need to come up with some additional limitations for
> > using the “counted_by”
> > attribute for pointer fields at the source code level in order to avoid
> > such potential error. But not
> > sure what exactly the additional limitation should be at this moment.
> >
> > Need some study here.
>
> Actually, I found out that this is really not a problem with the current
> design, for the following new testing case I added for my current
> implementation of the counted_by for pointer field:
>
> [ gcc.dg]$ cat pointer-counted-by-7.c
> /* Test the attribute counted_by for pointer field and its usage in
> * __builtin_dynamic_object_size. */
> /* { dg-do run } */
> /* { dg-options "-O2" } */
>
> #include "builtin-object-size-common.h"
>
> struct annotated {
> int b;
> int *c __attribute__ ((counted_by (b)));
> };
>
> struct annotated *__attribute__((__noinline__)) setup (int attr_count)
> {
> struct annotated *p_array_annotated
> = (struct annotated *) malloc (sizeof (struct annotated));
> p_array_annotated->c = (int *) malloc (sizeof (int) * attr_count);
> p_array_annotated->b = attr_count;
>
> return p_array_annotated;
> }
>
>
> int main(int argc, char *argv[])
> {
> struct annotated *x = setup (10);
> int *p = x->c;
> x = setup (20);
> EXPECT(__builtin_dynamic_object_size (p, 1), 10 * sizeof (int));
> EXPECT(__builtin_dynamic_object_size (x->c, 1), 20 * sizeof (int));
> DONE ();
> }
>
> This test case passed without any issue.
>
> Our previous introduction of the new internal function .ACCESS_WITH_SIZE
> already resolved this issue.
>
> So, I think that as long as the whole structure is set at the same time,
> should be fine.
>
> Let me know if you have more comment here.
I think the relevant scenario is where you assign the struct and
not a pointer to the struct, i.e. something like the following:
#include "builtin-object-size-common.h"
struct annotated {
int b;
int *c __attribute__ ((counted_by (b)));
};
struct annotated __attribute__((__noinline__)) setup (int attr_count)
{
struct annotated p_array_annotated;
p_array_annotated.c = (int *) malloc (sizeof (int) * attr_count);
p_array_annotated.b = attr_count;
return p_array_annotated;
}
int main(int argc, char *argv[])
{
struct annotated x = setup (10);
int *p = x.c;
x = setup (20);
EXPECT(__builtin_dynamic_object_size (p, 1), 10 * sizeof (int));
EXPECT(__builtin_dynamic_object_size (x.c, 1), 20 * sizeof (int));
DONE ();
}
Martin