Am Donnerstag, dem 10.04.2025 um 17:05 +0000 schrieb Qing Zhao:
> Hi, Martin,
> 
> Thanks a lot for all your comments and questions, really helpful.
> 
> 

...
> > 
> > An example I could imagine is when you memcpy
> > the struct.   (but it is also not entirely clear why this
> > should not be allowed to go beyond the counted_by size
> > if the underlying storage is larger).  
> > 
> > Maybe you could add it when a pointer to an annotated
> > struct is passed as parameter, but also there it is not
> > clear to me that we might want to materialize new
> > accesses to the struct at this point.
> 
> This is true too,  and this is even true for the current implementation for 
> p->array,
> as I checked with a small example as below:
> 
> [opc@qinzhao-aarch64-ol8 counted_by_whole]$ cat t2.c
> #include <stdlib.h>
> #include <stddef.h>
> 
> struct annotated {
>   size_t count;
>   char array[];  
> };
> 
> static size_t __attribute__((__noinline__,__noipa__)) size_of (struct 
> annotated * obj)
> {
>   return __builtin_dynamic_object_size (obj->array, 1);
> }
> 
> int main()
> {
>   __builtin_printf ("the bdos whole is %ld\n", size_of (0));
>   return 0;
> }
> 
> In the above example, the parameter to the function “size_of” has pointer 
> type to “struct annotated”,
> However, I passed a NULL to “size_of”, is this legal C? Looks like -Wall did 
> not issue any warning 
> for it.

It is legal to pass a NULL pointer.  Here, the issue is
that the builtin does not evaluate its argument, so it
is perhaps surprising that you can get a segfault.  If
the access it outside of the builtin, then this is not
a problem

static size_t __attribute__((__noinline__,__noipa__)) size_of (struct annotated 
* obj)
{
  char *p = obj->array;
  return __builtin_dynamic_object_size (p, 1);
}

because you get the segault anyway when the first line
is executed.

Maybe we need to document that the BDOS builtin requires
 obj->array  to be accessible even though it is not
evaluated.

But I wonder whether there are other cases where
the object-size path can walk into dead code and create
accesses in this way. Not sure, but I found this bug though:
https://godbolt.org/z/ejP918nW7

Martin

> 
> 
> [opc@qinzhao-aarch64-ol8 counted_by_whole]$ sh t
> /home/opc/Install/latest-d/bin/gcc -O2 -Wall t2.c
> the bdos whole is -1
> 0
> 
> Then when I added the counted_by attribute for FAM array as:
> 
> [opc@qinzhao-aarch64-ol8 counted_by_whole]$ cat t2.c
> #include <stdlib.h>
> #include <stddef.h>
> 
> struct annotated {
>   size_t count;
>   char array[] __attribute__ ((counted_by(count)));  
> };
> 
> static size_t __attribute__((__noinline__,__noipa__)) size_of (struct 
> annotated * obj)
> {
>   return __builtin_dynamic_object_size (obj->array, 1);
> }
> 
> int main()
> {
>   __builtin_printf ("the bdos whole is %ld\n", size_of (0));
>   return 0;
> }
> [opc@qinzhao-aarch64-ol8 counted_by_whole]$ sh t
> /home/opc/Install/latest-d/bin/gcc -O2 -Wall t2.c
> t: line 13: 2944007 Segmentation fault      (core dumped) ./a.out
> 139
> 
> This is because we insert the load from the &p->count for the size.
> 
> Qing
> 
> > 
> > An alternative approach could be to just do it when
> > such a pointer is explicitely passed to the BDOS builtin. 
> > 
> > Martin
> > 
> > 
> > > 
> > > Qing
> > > 
> > >  1 #include <stdlib.h>
> > >  2 #include <stddef.h>
> > >  3    
> > >  4 struct annotated {
> > >  5   size_t count;
> > >  6   char array[] __attribute__((counted_by (count)));
> > >  7 };
> > >  8 
> > >  9 /* compute the minimum # of bytes needed to hold a structure 
> > > “annotated”,
> > > 10    whose # of elements of “array” is COUNT.  */
> > > 11 #define MAX(A, B) (A > B) ? (A) : (B)
> > > 12 #define ALLOC_SIZE_ANNOTATED(COUNT) \
> > > 13   MAX(sizeof (struct annotated), \
> > > 14       offsetof(struct annotated, array[0]) + (COUNT) * sizeof(char))
> > > 15 
> > > 16 /* allocate the memory for the structure with FAM,
> > > 17    update “count” with the # of elements “index”.  */
> > > 18 static struct annotated * __attribute__((__noinline__)) alloc_buf (int 
> > > index)
> > > 19 {
> > > 20   struct annotated *p;
> > > 21   p = (struct annotated *) malloc (ALLOC_SIZE_ANNOTATED(index));
> > > 22   p->count = index;
> > > 23   return p;
> > > 24 }
> > > 25 
> > > 26 static size_t __attribute__((__noinline__)) size_of (struct annotated 
> > > * obj)
> > > 27 {
> > > 28   return __builtin_dynamic_object_size (obj, 1);
> > > 29 }
> > > 30  
> > > 31 int main()
> > > 32 {
> > > 33   struct annotated *q = alloc_buf (10);
> > > 34   __builtin_printf ("the bdos whole is %d\n", size_of (q));
> > > 35   return 0;
> > > 36 }
> 
> 

Reply via email to