Hi Vincent,

Le 14/05/2016 19:08, Vincent Bernat a écrit :
  ❦ 14 mai 2016 15:20 +0200, Cyril Bonté <cyril.bo...@free.fr> :

What is the most important is to report this to the gcc maintainers so that
they can fix the bug. The fix will naturally flow into the distros.


I understand this and of course I could try to fill a bug on their side but
the gcc stuff is a bit out of my league.

After spending some time on this, I'm now able to produce a minimal
test case.

$ gcc-6 -O2 -o debug debug.c && ./debug
0
=> here we have an issue, as it shouldn't be 0

$ gcc-6 -O2 -DDEBUG -o debug debug.c && ./debug
7f000001
7f000001
=> Suddenly, everything works

And now, what happens with this debug code when -fno-tree-sra is used ?
$ gcc-6 -O2 -fno-tree-sra -DDEBUG -o debug debug.c && ./debug
7f000001
0
=> It still doesn't work :-( So, disabling "tree-sra" doesn't
guarantee the right behaviour.

I also attach a debug2.c example, which is also disturbing. It is the
same code, but adds a local variable. Depending on the code order,
strange things happen (looks like a memory alignment issue).
For example :
$ gcc-6 -O2 -o debug2 debug2.c && ./debug2
0
fd7f0000

Note : my tests were made on a Debian SID with the gcc-6 package.

I think this is an aliasing problem. You cannot have two incompatible
variables pointing at the same memory spot. It seems that now
sockaddr_storage and sockaddr_in are not compatible anymore.

#v+
struct sockaddr_storage
   {
     __SOCKADDR_COMMON (ss_);    /* Address family, etc.  */
     __ss_aligntype __ss_align;  /* Force desired alignment.  */
     char __ss_padding[_SS_PADSIZE];
   };

struct sockaddr_in
   {
     __SOCKADDR_COMMON (sin_);
     in_port_t sin_port;                 /* Port number.  */
     struct in_addr sin_addr;            /* Internet address.  */

     /* Pad to size of `struct sockaddr'.  */
     unsigned char sin_zero[sizeof (struct sockaddr) -
                            __SOCKADDR_COMMON_SIZE -
                            sizeof (in_port_t) -
                            sizeof (struct in_addr)];
   };
#v-

If I introduce this type:

#v+
struct  sockaddr_storage_universal {
        union {
                struct sockaddr_storage sas;
                struct sockaddr_in sai;
                struct sockaddr_in6 sai6;
        };
};
#v-

This works when used in place of "struct sockaddr_storage". I see the
glibc is using an union too instead of struct sockaddr or struct
sockaddr_storage. man 7 socket still says to use struct
sockaddr_storage.

Searching a bit, there is this old question on StackOverflow:
  
http://stackoverflow.com/questions/1429645/how-to-cast-sockaddr-storage-and-avoid-breaking-strict-aliasing-rules

Yes, that's where I stopped too after extracting the test case from the whole code.


--
Cyril Bonté

Reply via email to