On 09/06/2016 08:16 AM, Joseph Myers wrote:
I don't think there's any such requirement in the case of flexible array
members; if you use malloc to allocate a structure with a flexible array
member, you can access as many trailing array elements as would fit within
the allocated size, whether or not that size is a multiple of either the
alignment of the structure, or the alignment of max_align_t.

Although I would prefer you to be correct I'm afraid the standard doesn't agree, as C11's wording appears to allow the GCC optimization in question. (At least, draft N1570 does; I don't have the final standard.) C11 section 6.7.2.1 paragraph 18 says:

"when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed"

Suppose 'short' size and alignment is 2, and the following code allocates and uses 7 bytes:

  struct s { short n; char a[]; } *p = malloc (offsetof (struct s, a) + 5);

  return &p->a[5];

A strict reading of C11 says this code is supposed to behave as if 'char a[];' were replaced by 'char a[4];'. It is not the 'char a[5]' that one might expect, because using 'char a[5];' would mean the size of struct s (after alignment) would be 8, whereas the size of the object being accessed is only 7. Hence the above return expression has a subscript error.

One way to correct the code is to increase malloc's argument up to a multiple of alignof(max_align_t). (One cannot portably use alignof(struct s) due to C11's prohibition of using alignof on incomplete types.) This is why gnulib/lib/fts.c uses max_align_t.

Reply via email to