[CC += Kees, Andrew] [start of thread: <https://inbox.sourceware.org/gcc/[email protected]/T/#u>]
On 5/11/23 18:07, Alejandro Colomar wrote:
> Hi!
>
> Currently, one can have pseudo-flexible array members in unions with
> [0] syntax, but it's not allowed with [] syntax.
>
> Here's an example of how it is possible today:
>
> struct s {
> ...
>
> size_t n;
> union {
> ptrdiff_t off[0]; // [n]; offsets from s->data.
> char data[0];
> };
> };
>
> which is useful to have a structure with two (or really several)
> consecutive flexible arrays: one of offsets, which mark the positions
> of data, and another with the actual data. Below goes an example
> program, which works fine with GCC, and I believe rewriting it to
> not use the union would make it less clear, since I'd need to add
> casts to it.
>
> It works thanks to [0] pseudo-flexible arrays, but it doesn't
> compile with C99 flexible arrays. And of course, [0] arrays have
> issues with -fstrict-flex-arrays=3.
>
>
> $ cat flexi4.c
> #include <stddef.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
>
> struct s {
> size_t n;
> union {
> ptrdiff_t off[0];
> char data[0];
> };
> };
>
> int
> main(void)
> {
> char *p;
> struct s *s;
>
> s = malloc(offsetof(struct s, off) +
> sizeof(ptrdiff_t) * 2 +
> sizeof("foobar") + sizeof("baz"));
>
> s->n = 2;
> p = s->data + sizeof(ptrdiff_t) * s->n;
>
> s->off[0] = p - s->data;
> p = stpcpy(p, "foobar") + 1;
> s->off[1] = p - s->data;
> p = stpcpy(p, "baz") + 1;
>
> puts(s->data + s->off[0]);
> puts(s->data + s->off[1]);
>
> free(s);
> }
> $ gcc-13 -Wall -Wextra -Werror -fanalyzer \
> -fsanitize=undefined -fsanitize=address \
> -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=2 \
> flexi4.c
> $ ./a.out
> foobar
> baz
> $ gcc-13 -Wall -Wextra -Werror -fanalyzer \
> -fsanitize=undefined -fsanitize=address \
> -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=3 \
> flexi4.c
> $ ./a.out
> flexi4.c:27:8: runtime error: index 0 out of bounds for type 'ptrdiff_t [*]'
> flexi4.c:29:8: runtime error: index 1 out of bounds for type 'ptrdiff_t [*]'
> flexi4.c:32:23: runtime error: index 0 out of bounds for type 'ptrdiff_t [*]'
> foobar
> flexi4.c:33:23: runtime error: index 1 out of bounds for type 'ptrdiff_t [*]'
> baz
>
>
> Would you allow flexible array members in unions? Is there any
> strong reason to disallow them?
>
> Currently, I get:
>
> $ gcc-13 -Wall -Wextra -fanalyzer \
> -fsanitize=undefined -fsanitize=address \
> -D_FORTIFY_SOURCE=3 -fstrict-flex-arrays=3 \
> flexi4-true.c
> flexi4-true.c:9:28: error: flexible array member in union
> 9 | ptrdiff_t off[];
> | ^~~
> flexi4-true.c:10:28: error: flexible array member in union
> 10 | char data[];
> | ^~~~
>
>
Currently, the Linux kernel has to go through some hoops due to this
restriction:
$ grepc -tm __DECLARE_FLEX_ARRAY *
include/uapi/linux/stddef.h:42:
#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
struct { \
struct { } __empty_ ## NAME; \
TYPE NAME[]; \
}
tools/include/uapi/linux/stddef.h:42:
#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
struct { \
struct { } __empty_ ## NAME; \
TYPE NAME[]; \
}
$ grep -rnB2 __DECLARE_FLEX_ARRAY * | head
include/uapi/rdma/rdma_user_rxe.h-153- __u32 reserved;
include/uapi/rdma/rdma_user_rxe.h-154- union {
include/uapi/rdma/rdma_user_rxe.h:155: __DECLARE_FLEX_ARRAY(__u8,
inline_data);
include/uapi/rdma/rdma_user_rxe.h:156: __DECLARE_FLEX_ARRAY(__u8,
atomic_wr);
include/uapi/rdma/rdma_user_rxe.h:157: __DECLARE_FLEX_ARRAY(struct
rxe_sge, sge);
--
include/uapi/scsi/scsi_netlink_fc.h-53- union {
include/uapi/scsi/scsi_netlink_fc.h-54- __u32 event_data;
include/uapi/scsi/scsi_netlink_fc.h:55: __DECLARE_FLEX_ARRAY(__u8,
event_data_flex);
--
--
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5
OpenPGP_signature
Description: OpenPGP digital signature
