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

Reply via email to