gcc doesn't isssue a strict aliasing warning on a code that seems to break it

Bug #1072650 reported by Rafal Wojtczuk
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
gcc-defaults
Confirmed
Medium
gcc-defaults (Ubuntu)
Confirmed
Undecided
Unassigned

Bug Description

The repro code (attached below), when compiled under Ubuntu 12.04 LTS on x86_64, with -O2 flag, produces incorrect code.
As seen in the disassembly, the assignment to hdr.saddr is completely optimized out, and subsequent accesses to this field reads garbage from the stack.
Without -02, or on x86_32, the code is correct (so on x86_64, the same program compiled with -O2 produces different output than the one compiled without -O2).
At least on one other 64bit system (Fedora 14), gcc -O2 produces correct code. This looks like a gcc bug, specific to the particular version.
Because of this bug, libnids library is not working on x86_64 12.04 LTS (as originally reported by Carlos Vega, <email address hidden>).

========== Repro code =========
#include <stdio.h>

struct psuedo_hdr
{
  int saddr;
  int daddr;
  char zero;
  char protocol;
  short len;
} __attribute__((packed));

main()
{
  unsigned int i;
  unsigned int sum = 0;
  struct psuedo_hdr hdr;

  hdr.saddr = 0xaabbccdd;
  hdr.daddr = 0x11223344;
  hdr.zero = 0;
  hdr.protocol = 6;
  hdr.len = 2;
  for (i = 0; i < sizeof(hdr); i += 2)
    sum += *(short *)((char *)(&hdr) + i);
  printf("0x%x\n", sum);
  return 0;
}
==== Repro code end ====

==== packages versions ====
user@user-MS-7808:~/gccbug$ dpkg -s gcc binutils
Package: gcc
Status: install ok installed
Priority: optional
Section: devel
Installed-Size: 41
Maintainer: Ubuntu Developers <email address hidden>
Architecture: amd64
Source: gcc-defaults (1.112ubuntu5)
Version: 4:4.6.3-1ubuntu5
Provides: c-compiler
Depends: cpp (>= 4:4.6.3-1ubuntu5), gcc-4.6 (>= 4.6.3-1~)
Recommends: libc6-dev | libc-dev
Suggests: gcc-multilib, make, manpages-dev, autoconf, automake1.9, libtool,
flex, bison, gdb, gcc-doc
Conflicts: gcc-doc (<< 1:2.95.3)
Description: GNU C compiler
 This is the GNU C compiler, a fairly portable optimizing compiler for C.
 .
 This is a dependency package providing the default GNU C compiler.
Original-Maintainer: Debian GCC Maintainers <email address hidden>

Package: binutils
Status: install ok installed
Priority: optional
Section: devel
Installed-Size: 8564
Maintainer: Ubuntu Core developers <email address hidden>
Architecture: amd64
Version: 2.22-6ubuntu1
Replaces: binutils-gold (<< 2.20.51.20100415)
Provides: elf-binutils
Depends: libc6 (>= 2.14), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.6), zlib1g
(>= 1:1.2.0)
Suggests: binutils-doc (>= 2.22-6ubuntu1)
Conflicts: binutils-gold (<< 2.20.51.20100415), elf-binutils, gas, modutils
(<< 2.4.19-1)
Description: GNU assembler, linker and binary utilities
 The programs in this package are used to assemble, link and manipulate
 binary and object files. They may be used in conjunction with a compiler
 and various libraries to build programs.
Original-Maintainer: Matthias Klose <email address hidden>

=== packages version end ====

==== disassembly of code produced with -O2 ====
0000000000400440 <main>:
  400440: 48 83 ec 18 sub $0x18,%rsp
  400444: 31 d2 xor %edx,%edx
  400446: 48 8d 74 24 0c lea 0xc(%rsp),%rsi
  40044b: c6 44 24 08 00 movb $0x0,0x8(%rsp)
  400450: c6 44 24 09 06 movb $0x6,0x9(%rsp)
  400455: 66 c7 44 24 0a 02 00 movw $0x2,0xa(%rsp)
  40045c: 48 89 e0 mov %rsp,%rax
  40045f: 90 nop
  400460: 0f bf 08 movswl (%rax),%ecx
  400463: 48 83 c0 02 add $0x2,%rax
  400467: 01 ca add %ecx,%edx
  400469: 48 39 f0 cmp %rsi,%rax
  40046c: 75 f2 jne 400460 <main+0x20>
  40046e: be 5c 06 40 00 mov $0x40065c,%esi
  400473: bf 01 00 00 00 mov $0x1,%edi
  400478: 31 c0 xor %eax,%eax
  40047a: e8 b1 ff ff ff callq 400430 <__printf_chk@plt>
  40047f: 31 c0 xor %eax,%eax
  400481: 48 83 c4 18 add $0x18,%rsp
  400485: c3 retq
  400486: 90 nop
  400487: 90 nop

Revision history for this message
David (edeca) wrote :

Still causing an issue with libnids-1.24 on gcc version 4.7.3 (Gentoo 4.7.3-r1 p1.4, pie-0.5.5). Using -O1 with this compiler is successful on AMD64.

Revision history for this message
Rafał Mużyło (galtgendo) wrote :

The bug in gcc seems to be not printing "dereferencing type-punned pointer will break strict-aliasing rules" warning, as either '-fno-strict-aliasing' or wrapping the struct in an union with short[6] seems to fix the problem.

On not quite related note: would have been nice if the intended output of that test program was noted. While you can calculate it on your own, it would make for a better testcase.

Revision history for this message
In , Rafał Mużyło (galtgendo) wrote :

The problem is described here: https://bugs.gentoo.org/show_bug.cgi?id=505026
The code to trigger comes from a launchpad bug: https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1072650

As you may notice, it's acros distros and affects many compiler versions (confirmed for 4.6.3 on ubuntu, 4.7.3 and 4.8.2 on Gentoo).

Following code (AFAICT) violates strict aliasing rules:
#include <stdio.h>

struct psuedo_hdr
{
  int saddr;
  int daddr;
  char zero;
  char protocol;
  short len;
} __attribute__((packed));

int main()
{
  unsigned int i;
  unsigned int sum = 0;
  struct psuedo_hdr hdr;

  hdr.saddr = 0xaabbccdd;
  hdr.daddr = 0x11223344;
  hdr.zero = 0;
  hdr.protocol = 6;
  hdr.len = 2;
  for (i = 0; i < sizeof(hdr); i += 2)
    sum += *(short *)((char *)(&hdr) + i);
  printf("0x%x\n", sum);
  return 0;
}

however, '-O2 -Wall' doesn't result in the strict aliasing warning.

Revision history for this message
David (edeca) wrote :

Also see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60581 (reported upstream to GCC by Rafał) and https://bugs.gentoo.org/show_bug.cgi?id=505026 (further discussion of why this has occurred).

Revision history for this message
In , Rguenth (rguenth) wrote :

The strict-aliasing warnings are broken - they are too easily to silence (the (char *) cast for example). Generally warning for TBAA violations is very hard if you want to avoid gazillions of false positives or gazillions of false negatives. The present warning code delivers neither :/

Matthias Klose (doko)
summary: - gcc -O2 produces incorrect code for accessing struct by its address
+ gcc doesn't isssue a strict aliasing warning on a code that seems to
+ break it
Changed in gcc-defaults (Ubuntu):
status: New → Confirmed
Changed in gcc-defaults:
importance: Unknown → Medium
status: Unknown → Confirmed
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.