Dear developers,
May I seek your help with some understanding of why GCC produces the
wrong-code bug? I understand that such a bug can only be reproduced in an
old GCC version, but I still want to know why GCC made mistake here.
The bug-revealing code makes GCC-4.7.0 produce miscompiled code under the
-O3 option.
$gcc-4.7.0 -O1 s.c -o s1; ./s1
Aborted (core dumped)
$gcc-4.7.0 -O3 s.c -o s2; ./s2
Please check the source code of the code (s.c) and the assembly code of the
main function below.
```
//s.c
int a = 0;
int b[10] = {0};
__attribute__((noinline))
void marker() {
if (a)
__builtin_abort();
}
void func1() { a++;}
int main() {
int e;
for (e = 0; e <= 4; e++) {
marker();
b[e] = 0;
func1();
}
}
```
The assembly code of the main function:
s1:
0000000000401156 <main>:
401156: 55 push %rbp
401157: 53 push %rbx
401158: 48 83 ec 08 sub $0x8,%rsp
40115c: bb 60 40 40 00 mov $0x404060,%ebx
401161: bd 74 40 40 00 mov $0x404074,%ebp
401166: b8 00 00 00 00 mov $0x0,%eax
40116b: e8 ca ff ff ff callq 40113a <marker>
401170: c7 03 00 00 00 00 movl $0x0,(%rbx)
401176: b8 00 00 00 00 mov $0x0,%eax
40117b: e8 ce ff ff ff callq 40114e <func1>
401180: 48 83 c3 04 add $0x4,%rbx
401184: 48 39 eb cmp %rbp,%rbx
401187: 75 dd jne 401166 <main+0x10>
401189: 48 83 c4 08 add $0x8,%rsp
40118d: 5b pop %rbx
40118e: 5d pop %rbp
40118f: c3 retq
s2:
0000000000401040 <main>:
401040: 8b 05 4a 30 00 00 mov 0x304a(%rip),%eax #
404090 <a>
401046: 48 c7 05 0f 30 00 00 movq $0x0,0x300f(%rip) #
404060 <b>
40104d: 00 00 00 00
401051: 48 c7 05 0c 30 00 00 movq $0x0,0x300c(%rip) #
404068 <b+0x8>
401058: 00 00 00 00
40105c: c7 05 0a 30 00 00 00 movl $0x0,0x300a(%rip) #
404070 <b+0x10>
401063: 00 00 00
401066: 83 c0 05 add $0x5,%eax
401069: 89 05 21 30 00 00 mov %eax,0x3021(%rip) #
404090 <a>
40106f: c3 retq
I think s.c is well-defined and does not involve any undefined behaviors. I
have the following two main questions regarding this bug.
(1) The root cause of the bug. It seems that some live code (the code block
in the for loop) inside the main function is eliminated in the miscompiled
binary under the -O3 optimization. My best guess of the root cause is that
GCC-4.7.0 has some issues with loop optimization, which makes the dead code
elimination optimization wrongly eliminates the live code. Am I right here
or how can I check the root cause of this bug? Are there any existing bug
reports indicating this issue?
(2) About the DCE (dead code elimination). In practice, for modern
compilers, especially for GCC (and LLVM), are there any other optimization
passes apart from DCE that can eliminate dead code blocks as well? is there
any evidence that could support the claim? In other words, can I draw a
conclusion that if a live code (code blocks rather than single
instructions) is eliminated under higher optimizations, it must be directly
(DCE itself eliminates a live code) or indirectly (other optimizations
affect the decision in DCE to eliminate a live code block) caused by a DCE
issue?
Any ideas or comments are welcome! Thank you very much!
Best regards,
Haoxin