[Bug target/80334] [7 Regression] Segfault when taking address of copy of unaligned struct

jakub at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Thu Apr 6 09:20:00 GMT 2017


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80334

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Testcase without STL headers:
struct A { alignas(16) char c; };
struct B { A unpacked; char d; } __attribute__((packed));

int
main()
{
  alignas(16) B b[3];
  for (int i = 0; i < 3; i++) b[i].unpacked.c = 'a' + i;
  for (int i = 0; i < 3; i++) {
    auto a = new A(b[i].unpacked);
    __builtin_printf ("%c\n", a->c);
  }
}

Not really sure if this is valid testcase though, by placing it into an array
you are violating the alignments of the fields in second and following
elements.
If you want to align just the start of the array, put the alignas on the array,
not on the types.

At expansion (and likely already in GIMPLE) we are assuming 128-bit alignment
of b[i].unpacked):
(mem:TI (reg:DI 105 [ ivtmp.9 ]) [1 MEM[base: _21, offset: 0B]+0 S16 A128]))
so this is not STV's pass fault, just that when using vector insns the target
behaves as strict alignment rather than forgiving all alignment violations.

If you use
struct A { long long c; };
struct B { A unpacked; char d; } __attribute__((packed));

int
main()
{
  B b[3];
  for (int i = 0; i < 3; i++) b[i].unpacked.c = 'a' + i;
  for (int i = 0; i < 3; i++) {
    auto a = new A(b[i].unpacked);
    __builtin_printf ("%c\n", a->c);
  }
}
then we assume 64-bit alignment on the b[i].unpacked read too.

With
struct A { char c __attribute__((aligned (16))); };
struct B { A unpacked; char d; } __attribute__((packed));

int
main()
{
  B b[3] __attribute__((aligned (16)));
  for (int i = 0; i < 3; i++) b[i].unpacked.c = 'a' + i;
  for (int i = 0; i < 3; i++) {
    A *a = new A(b[i].unpacked);
    __builtin_printf ("%c\n", a->c);
  }
}
and -O2 I can track the using of A128 in the read from b[i].unpacked to
r162001,
and r161703 still emits there A8.
r161703 in *.optimized still has:
  D.2157_35 = (void *) ivtmp.10_27;
  *a_11 = MEM[base: D.2157_35];
and in *.vregs has:
(insn 17 16 18 4 pr80334-3.C:10 (set (reg:DI 69)
        (mem/s:DI (reg:DI 63 [ ivtmp.10 ]) [2 b[i].unpacked+0 S8 A8])) 61
{*movdi_internal_rex64} (nil))
No idea where it discovered the b[i].unpacked!
r162001 has in *.optimized:
  D.2157_35 = (void *) ivtmp.10_27;
  *a_11 = MEM[(struct B[3] *)D.2157_35];
and in *.vregs:
(insn 17 16 18 4 pr80334-3.C:10 (set (reg:DI 69)
        (mem/s:DI (reg:DI 63 [ ivtmp.10 ]) [3 MEM[(struct B[3] *)D.2157_35]+0
S8 A128])) 61 {*movdi_internal_rex64} (nil))

Unfortunately various revisions between those 2 (don't have that many) just
hang on the testcase, so can't bisect it exactly.


More information about the Gcc-bugs mailing list