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