gcc may miscompile code on i386 using kernel sigsetadd if signal argument is constant. The probem is also reproducible in user space. All versions of gcc and all versiong of kernels are affected. Attached please find a program that can be compiled into module or executable. If compiled with -O2 flags, the resulting code is wrong. Disassembly (or running in the debugger) shows miscompilation. Disabling optimization or just using -O fixes the problem. In short the following code is problematic: sigset_t a; sigset_t b; sigset_t c; ........... sigaddset(&a, const1); sigaddset(&a, const2); ................................ b =a; /* this line causes incorrect code; any 64-bit assignment seems to cause a problem! */ sigaddset(&c, const2); sigaddset(&c, const3); /* more sigaddset to c */ At some iteration of sigaddset to c, c may get the value of a!!!
Created attachment 121166 [details] A sample of c code that gets miscompiled if -O2 flags is used.
That's just buggy testcase. static __inline__ void __gen_sigaddset(sigset_t *set, int _sig) { __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig-1) : "cc"); } You need either __asm__("btsl %1,%0" : "+m"(*set) : "Ir"(_sig-1) : "cc"); or __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig-1), "m"(*set) : "cc"); because the btsl instruction doesn't just set the memory to some value, but needs to read its previous content as well. If you don't tell that fact to GCC, GCC is of course free to optimize as if the asm was just setting the value and not depended on the previous value.