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 }
>
>