https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97943
Bug ID: 97943 Summary: [11 Regression] ICE with __builtin_clear_padding on flexible array member Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org Target Milestone: --- struct S { int a; char b[] __attribute__((aligned (2 * sizeof (int)))); }; void foo (struct S *u) { __builtin_clear_padding (u); } ICEs starting with the __builtin_clear_padding implementation r11-5196-g1bea0d0aa5936cb36b6f86f721ca03c1a1bb601d Avoiding the ICE is easy, e.g. --- gcc/gimple-fold.c.jj 2020-11-20 12:28:10.102680956 +0100 +++ gcc/gimple-fold.c 2020-11-22 21:54:39.527918551 +0100 @@ -4439,6 +4439,12 @@ clear_padding_type (clear_padding_struct } } } + else if (DECL_SIZE_UNIT (field) == NULL_TREE) + { + gcc_assert (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE + && !COMPLETE_TYPE_P (TREE_TYPE (field))); + /* Flexible array member. Consider it all padding. */ + } else { HOST_WIDE_INT pos = int_byte_position (field); the important question is what behavior we want in that case. The above patch will make all the bits in the tail padding starting with the address of the flexible array member till the end of the type in question padding bits (plus the padding before the flexible array member but that is not questionable). The problem with that is that if the object does contain any flexible array members, __builtin_clear_padding could then clear even the value representation of those array elements. Another approach would be to consider that the flexible array member contains as many elements as can (even partially) fit into the type bounds. So e.g. if we have: struct S { char a; short b; char c; }; struct T { char a; struct S b __attribute__((aligned (32))); S c[]; }; the padding mask (0 for padding, 1 for unmodified value) for struct S is 0xff, 0, 0xff, 0xff, 0xff, 0 and for T it would be 0xff, 31x 0, (now is b field) 0xff, 0, 0xff, 0xff, 0xff, 0, (now starts the flex array member and we 32-6 bytes in the tail padding), so we repeat 0xff, 0, 0xff, 0xff, 0xff, 0 there 4 times (that fits in full) and then 0xff, 0 (first two bytes of the element that would cross the size of the T type we were passed pointer to). Thoughts on this? If we go the latter route, there are complications on what to do if a structure with flexible array member is embedded into other structures or unions. And in those it can go either in places where it is followed by other fields, or no real fields after it. So given the above struct S and T, if we have: struct U { char a __attribute__((aligned (128))); struct T b; }; U's size is 256 bytes, would the padding be 0xff, 127x 0, then for T 0xff, 31x 0, then 16x ( 0xff, 0, 0xff, 0xff, 0xff, 0 ) , i.e. as if c[] was actually c[15] in this case? If there are fields after it, instead consider only what is the largest number that would fit in before that next field without partial elements? For the implementation, we'd probably need to pass down the size of the padding before the next element (if any), or end of the type and for the flexible array members compute from there how many elements and whether full or partial one can fit. If there following fields are bitfields, I have no idea, though I'd say the elements shouldn't cross even unnamed bitfields. struct V { struct T a; int : 30; int c : 2; };