On 2023-08-11 20:29, Alejandro Colomar wrote: > Hi! > > Structures with flexible array members have restrictions about being > used in arrays or within other structures, as the size of the enclosing > aggregate type would be... inconsistent. > > In general, sizeof(flexible_struct) is a problematic thing that rarely > means what programmers think it means. It is not the size of the > structure up to the flexible array member; or expressed using C, > the following can be true: > > sizeof(s) != offsetof(s, fam) > > See the program at the bottom that demonstrates how this is problematic. > > It's true that if one uses > > malloc(offseof(s, fam) + sizeof_member(s, fam[0]) * N); > > and N is very small (0 or 1 usually), the allocation would be smaller > than the object size, which for GCC seems to be fine, but I'm worried the > standard is not clear enough about its validity[1]. > > [1]: <https://software.codidact.com/posts/287754> > > To avoid having UB there, pedantically one would need to call > > malloc(MAX(sizeof(s), offseof(s, fam) + sizeof_member(s, fam[0]) * N)); > > But I think that's the only correct use of sizeof() with structures > containing flexible array members. So it seems sizeof() by itself is > a valid thing, but when adding it to something else to get the total size, > or doing any arithmetic with it, that's dubious code. > > How about some -Wfam-sizeof-arithmetic that would not warn about taking > sizeof(s) but would warn if that sizeof is used in any arithmetic? > > Cheers, > Alex > > --- > > $ cat off.c > #include <err.h> > #include <stddef.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > > > struct s { > int i; > char c; > char fam[]; > }; > > > static inline void *xmalloc(size_t size); > > > int > main(void) > { > char *p; > struct s *s; > > printf("sizeof: %zu\n", sizeof(struct s)); > printf("offsetof: %zu\n", offsetof(struct s, fam)); > > puts("\nWith sizeof():"); > > s = xmalloc(sizeof(struct s) + sizeof("Hello, sizeof!")); > strcpy(s->fam, "Hello, sizeof!"); > p = (char *) s + sizeof(struct s); > puts(p); > free(s); > > puts("\nWith offsetof(3):"); > > s = xmalloc(offsetof(struct s, fam) + sizeof("Hello, offsetof!")); > strcpy(s->fam, "Hello, offsetof!"); > p = (char *) s + offsetof(struct s, fam); > puts(p); > free(s); > > exit(EXIT_SUCCESS); > } > > > static inline void * > xmalloc(size_t size) > { > void *p; > > p = malloc(size); > if (p == NULL) > err(EXIT_FAILURE, "malloc"); > return p; > } > $ gcc-13 -Wall -Wextra -Wpadded -fanalyzer off.c > off.c:12:1: warning: padding struct size to alignment boundary with 3 bytes > [-Wpadded] > 12 | }; > | ^
I forgot to paste the output of the program:) $ ./a.out sizeof: 8 offsetof: 5 With sizeof(): lo, sizeof! With offsetof(3): Hello, offsetof! > > > The only warning I know that is triggered in the code above is -Wpadded, > which is related to this problem, but I think there should be something > to warn about sizeof() in this context. > > -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5
OpenPGP_signature
Description: OpenPGP digital signature