Bug 91672 - wrong amount of storage allocated for initialized structs with flexible array members
Summary: wrong amount of storage allocated for initialized structs with flexible array...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
: 109956 (view as bug list)
Depends on:
Blocks: flexmembers
  Show dependency treegraph
 
Reported: 2019-09-05 16:31 UTC by Martin Sebor
Modified: 2024-03-14 23:21 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-09-06 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2019-09-05 16:31:29 UTC
Even though GCC takes advantage of tail padding when laying out structures with flexible array members, in C mode it allocates excess storage for statically initialized objects of such structs.

In the test case below, thanks to tail padding, sizeof (struct A) is sufficiently large to store each of a0 through a3.  But as the assembly output shows, the variables occupy more storage than necessary.

$ cat a.c && gcc -O2 -S -Wall -Wextra -o /dev/stdout -xc a.c | grep -e \.size
struct A
{
  __INT64_TYPE__ i64;
  __INT16_TYPE__ i16;
  __INT16_TYPE__ a16[];
};

struct A a0 = { 0, 1 };
struct A a1 = { 1, 1, { 1 } };
struct A a2 = { 2, 1, { 1, 2 } };
struct A a3 = { 3, 1, { 1, 2, 3 } };
struct A a4 = { 4, 1, { 1, 2, 3, 4 } };
	.size	a4, 24
	.size	a3, 22
	.size	a2, 20
	.size	a1, 18
	.size	a0, 16

G++ on the other hand, allocates the same amount of space regardless of the size of the initializer:

$ gcc -O2 -S -Wall -Wextra -o /dev/stdout -xc++ a.c | grep -e \.size
	.size	a4, 16
	.size	a3, 16
	.size	a2, 16
	.size	a1, 16
	.size	a0, 16

Clang allocates just the right amount, i.e., 16 bytes for a0 through a3 and 24 bytes for a4.
Comment 1 Andrew Pinski 2024-03-14 20:06:08 UTC
Note the C++ sizes was recorded as PR 102295 .
Comment 2 Andrew Pinski 2024-03-14 20:12:53 UTC
Note the .size does match up with what GCC outputs though:
e.g. a1:
        .size   a1, 18
a1:
        .xword  1
        .hword  1
        .hword  1
        .zero   6

that is size of 18.
Basically gcc's padding is always 6 in size and not changing based on the size that is needed there.

This is also normally how you get the size when allocating dynamically too:

sizeof(struct A) + N*sizeof(__INT16_TYPE__).
Comment 3 Andrew Pinski 2024-03-14 20:17:51 UTC
*** Bug 109956 has been marked as a duplicate of this bug. ***