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


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

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

Reply via email to