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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
   Last reconfirmed|                            |2020-02-17
                 CC|                            |jakub at gcc dot gnu.org
         Resolution|INVALID                     |---
     Ever confirmed|0                           |1

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I've bisected this (well, lzo 2.08) to src/lzo_init.c, -O2 -fno-strict-aliasing
it still works, with -O2 it fails, and at least in the past lzo has been known
to violate strict aliasing even in this TU.
The "miscompilation" started with
r10-514-gc6b84edb6110dd2b4fb654c53c0a9979e0532ffe and the difference between
r10-513 and r10-514 is:
 _lzo_config_check:
        pushq   %r15
        xorl    %esi, %esi
        pushq   %r14
        pushq   %r13
        pushq   %r12
        pushq   %rbp
        pushq   %rbx
        movabsq $4398046511107, %rbx
        subq    $24, %rsp
        movq    %rsp, %rdi
        movq    $0, (%rsp)
        movq    $0, 8(%rsp)
        call    u2p
        movl    $1, %esi
        cmpb    $0, (%rax)
-       movb    $-128, (%rsp)
        sete    %dl
        cmpq    $128, (%rax)
-       movq    $33554433, (%rsp)
+       movb    $1, (%rsp)
        sete    %r13b
+       movb    $2, 3(%rsp)
        call    u2p
where 33554433 is 0x02000001, so the difference is that the 1(%rsp) and 2(%rsp)
bytes are no longer initialized after the first u2p call.

Slightly reduced testcase for -O2:
typedef unsigned short int __attribute__((__may_alias__)) lzo_memops_TU2;
typedef unsigned int __attribute__((__may_alias__)) lzo_memops_TU4;
typedef unsigned long int __attribute__((__may_alias__)) lzo_memops_TU8;

union lzo_config_check_union {
  unsigned long a[2];
  unsigned char b[2*((8) >= (sizeof(unsigned long)) ? (8) : (sizeof(unsigned
long)))];
  unsigned long int c[2];
};

static __attribute__((noinline, noclone)) void * u2p(void * ptr, unsigned long
off)
{
  return (void *) ((unsigned char *) ptr + off);
}

__attribute__((noipa)) int
lzo_config_check(void)
{
  union lzo_config_check_union u;
  void *p;
  unsigned r = 1;
  u.a[0] = u.a[1] = 0;
  p = u2p(&u, 0);
  r &= ((* (unsigned char *) p) == 0);
  u.a[0] = u.a[1] = 0; u.b[0] = 128;
  p = u2p(&u, 0);
  r &= ((* (unsigned long *) p) == 128);
  u.a[0] = u.a[1] = 0;
  u.b[0] = 1; u.b[3] = 2;
  p = u2p(&u, 1);
  r &= * (const volatile lzo_memops_TU2 *) (const void *) (p) == 0;
  r &= * (const volatile lzo_memops_TU2 *) (const void *) (p) == 0;
  u.b[1] = 128;
  r &= * (const volatile lzo_memops_TU2 *) (const void *) (p) == 128;
  u.b[2] = 129;
  r &= * (const volatile lzo_memops_TU2 *) (const void *) (p) == (0x8180U);
  r &= * (const volatile lzo_memops_TU2 *) (const void *) (p) == (0x8180U);
  u.a[0] = u.a[1] = 0;
  u.b[0] = 3; u.b[5] = 4;
  p = u2p(&u, 1);
  r &= * (const volatile lzo_memops_TU4 *) (const void *) (p) == 0;
  r &= * (const volatile lzo_memops_TU4 *) (const void *) (p) == 0;
  u.b[1] = 128;
  r &= * (const volatile lzo_memops_TU4 *) (const void *) (p) == 128;
  u.b[2] = 129; u.b[3] = 130; u.b[4] = 131;
  r &= * (const volatile lzo_memops_TU4 *) (const void *) (p) == (0x83828180U);
  r &= * (const volatile lzo_memops_TU4 *) (const void *) (p) == (0x83828180U);
  u.c[0] = u.c[1] = 0;
  u.b[0] = 5; u.b[9] = 6;
  p = u2p(&u, 1);
  u.c[0] = u.c[1] = 0;
  r &= * (const volatile lzo_memops_TU8 *) (const void *) (p) == 0;
  r &= * (const volatile lzo_memops_TU8 *) (const void *) (p) == 0;
  u.b[1] = 128;
  r &= * (const volatile lzo_memops_TU8 *) (const void *) (p) == 128;
  return r == 1 ? 0 : (-1);
}

int
main ()
{
  if (lzo_config_check ())
    __builtin_abort ();
  return 0;
}

Now, with the casts to may_alias types I wonder if this isn't actually valid.

Reply via email to