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.