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

            Bug ID: 71120
           Summary: Aliasing "struct sockaddr_storage" produces invalid
                    code
           Product: gcc
           Version: 6.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: bernat at luffy dot cx
  Target Milestone: ---

Hello,

Starting with gcc-6, the following code (PoC found by Cyril Bonté) will produce
an unexpected result:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

struct dbg_listener {
        struct sockaddr_storage addr;
};

int main(int argc, char **argv)
{
        struct dbg_listener *l;
        struct sockaddr_storage ss, *ss2, ss3;

        memset(&ss3, 0, sizeof(ss3));
        ss3.ss_family = AF_INET;
        ((struct sockaddr_in *)&ss3)->sin_addr.s_addr = inet_addr("127.0.0.1");

        ss2 = &ss3;

        ss = *ss2;

        l = calloc(1, sizeof(*l));
        l->addr = ss;

        printf("%x\n", ntohl(((struct sockaddr_in
*)(&l->addr))->sin_addr.s_addr));
        exit(0);
}

This is a common pattern when handling socket addresses in a generic way. Even
when the code is compiled with -fno-strict-aliasing, the output is 0 while it
should be 7f000001.

$ gcc-6 -O2 -Wall -fno-strict-aliasing debug.c -o debug && ./debug
0

Using -O0 fixes the problem. Fixing the aliasing violation with an union fixes
the problem too. Using -fno-tree-sra fixes the problem too. Compiling with
gcc-5.3.1 fixes the problem too.

Here is a good starting point for the context of this bug (in HAProxy):
http://article.gmane.org/gmane.comp.web.haproxy/27924

Reply via email to