[LLVMbugs] [Bug 7369] New: Miscompilation with -O1 and above
bugzilla-daemon at llvm.org
bugzilla-daemon at llvm.org
Sun Jun 13 06:17:44 PDT 2010
http://llvm.org/bugs/show_bug.cgi?id=7369
Summary: Miscompilation with -O1 and above
Product: clang
Version: trunk
Platform: PC
OS/Version: Linux
Status: NEW
Severity: normal
Priority: P
Component: -New Bugs
AssignedTo: unassignedclangbugs at nondot.org
ReportedBy: pipping at exherbo.org
CC: llvmbugs at cs.uiuc.edu
I've hit a test failure with libsigsegv that I get with clang but not gcc 4.4.
Its main author, Bruno Haible, has been so kind to analyse this problem. Here
is what he wrote to me:
--------------------
I have clang version 1.0 installed:
$ clang --version
clang version 1.0 (http://llvm.org/svn/llvm-project/cfe/trunk 81046)
Target: x86_64-pc-linux-gnu
Thread model: posix
and what I find is that 'clang' is miscompiling the 'switch' statement of
tests/stackoverflow2.c when -O1 or higher is enabled.
How to reproduce:
- Fetch libsigsegv-2.8.tar.gz from ftp.gnu.org,
- Configure it with "mkdir build; cd build; ../configure CC=clang"
- "make"
- "make check"
When the stackoverflow2 program is compiled like this:
clang -DHAVE_CONFIG_H -I. -I../../tests -I.. -I../src -g -c
../../tests/stackoverflow2.c \
&& /bin/sh ../libtool --tag=CC --mode=link clang -g -o stackoverflow2
stackoverflow2.o ../src/libsigsegv.la
it works fine.
When it is compiled like this:
clang -DHAVE_CONFIG_H -I. -I../../tests -I.. -I../src -g -O1 -c
../../tests/stackoverflow2.c \
&& /bin/sh ../libtool --tag=CC --mode=link clang -g -O1 -o
stackoverflow2 stackoverflow2.o ../src/libsigsegv.la
it runs into the abort() call.
It happens when setjmp() returns with a value of 3.
The source code is:
===============================================================================
int
main ()
{
...
/* Provoke two stack overflows in a row. */
switch (setjmp (mainloop))
{
case -1:
printf ("emergency exit\n"); exit (1);
case 0: case 1:
printf ("Starting recursion pass %d.\n", pass + 1);
recurse (0);
printf ("no endless recursion?!\n"); exit (1);
case 2:
*(volatile int *) (page + 0x678) = 42;
break;
case 3:
*(volatile int *) 0 = 42;
break;
case 4:
break;
default:
abort ();
}
printf ("Test passed.\n");
exit (0);
}
===============================================================================
In the case that works, without optimization, the code looks like this:
===============================================================================
401042: e8 b9 f9 ff ff callq 400a00 <_setjmp at plt>
401047: 89 c1 mov %eax,%ecx
401049: ff c1 inc %ecx
40104b: 89 ca mov %ecx,%edx
40104d: 83 f9 05 cmp $0x5,%ecx
401050: 48 89 95 50 ff ff ff mov %rdx,-0xb0(%rbp)
401057: 0f 87 9d 00 00 00 ja 4010fa <main+0x25a>
40105d: 48 8b 85 50 ff ff ff mov -0xb0(%rbp),%rax
401064: 48 89 c1 mov %rax,%rcx
401067: 48 8b 0c cd 08 1c 40 mov 0x401c08(,%rcx,8),%rcx
0x401c08:
(gdb) print *(void*(*)[6]) 0x401c08
$1 = {0x401071, 0x40108c, 0x40108c, 0x4010d2, 0x4010e6, 0x4010f8}
401071: 30 c0 xor %al,%al
401073: b9 68 1d 40 00 mov $0x401d68,%ecx
401078: 48 89 cf mov %rcx,%rdi
40107b: e8 40 f9 ff ff callq 4009c0 <printf at plt>
401080: b8 01 00 00 00 mov $0x1,%eax
401085: 89 c7 mov %eax,%edi
401087: e8 84 f9 ff ff callq 400a10 <exit at plt>
40108c: 8b 04 25 e8 30 60 00 mov 0x6030e8,%eax
401093: 83 c0 01 add $0x1,%eax
401096: 30 c9 xor %cl,%cl
401098: ba 30 1d 40 00 mov $0x401d30,%edx
40109d: 48 89 d7 mov %rdx,%rdi
4010a0: 89 c6 mov %eax,%esi
4010a2: 88 c8 mov %cl,%al
4010a4: e8 17 f9 ff ff callq 4009c0 <printf at plt>
4010a9: b8 00 00 00 00 mov $0x0,%eax
4010ae: 89 c7 mov %eax,%edi
4010b0: e8 bb fd ff ff callq 400e70 <recurse>
4010b5: 30 c9 xor %cl,%cl
4010b7: ba 50 1d 40 00 mov $0x401d50,%edx
4010bc: 48 89 d7 mov %rdx,%rdi
4010bf: 88 c8 mov %cl,%al
4010c1: e8 fa f8 ff ff callq 4009c0 <printf at plt>
4010c6: b8 01 00 00 00 mov $0x1,%eax
4010cb: 89 c7 mov %eax,%edi
4010cd: e8 3e f9 ff ff callq 400a10 <exit at plt>
4010d2: 48 8b 04 25 20 31 60 mov 0x603120,%rax
4010d9: 00
4010da: c7 80 78 06 00 00 2a movl $0x2a,0x678(%rax)
4010e1: 00 00 00
4010e4: eb 19 jmp 4010ff <main+0x25f>
4010e6: 48 b8 00 00 00 00 00 mov $0x0,%rax
4010ed: 00 00 00
4010f0: c7 00 2a 00 00 00 movl $0x2a,(%rax)
4010f6: eb 07 jmp 4010ff <main+0x25f>
4010f8: eb 05 jmp 4010ff <main+0x25f>
4010fa: e8 e1 f8 ff ff callq 4009e0 <abort at plt>
===============================================================================
All right.
With -O1, the code looks like this:
===============================================================================
400ee5: e8 5e fb ff ff callq 400a48 <_setjmp at plt>
400eea: ff c0 inc %eax
400eec: 83 f8 05 cmp $0x5,%eax
400eef: 77 78 ja 400f69 <main+0x189>
400ef1: ff 24 c5 08 1a 40 00 jmpq *0x401a08(,%rax,8)
(gdb) print *(void*(*)[6]) 0x401a08
$1 = {0x400ef8, 0x400f0c, 0x400f0c, 0x400f3b, 0x400f69, 0x400f4c}
400ef8: bf 15 1c 40 00 mov $0x401c15,%edi
400efd: e8 36 fb ff ff callq 400a38 <puts at plt>
400f02: bf 01 00 00 00 mov $0x1,%edi
400f07: e8 4c fb ff ff callq 400a58 <exit at plt>
400f0c: 8b 35 d6 21 20 00 mov 0x2021d6(%rip),%esi #
6030e8 <pass>
400f12: ff c6 inc %esi
400f14: bf 30 1b 40 00 mov $0x401b30,%edi
400f19: 30 c0 xor %al,%al
400f1b: e8 d8 fa ff ff callq 4009f8 <printf at plt>
400f20: 31 ff xor %edi,%edi
400f22: e8 99 fe ff ff callq 400dc0 <recurse>
400f27: bf e0 1b 40 00 mov $0x401be0,%edi
400f2c: e8 07 fb ff ff callq 400a38 <puts at plt>
400f31: bf 01 00 00 00 mov $0x1,%edi
400f36: e8 1d fb ff ff callq 400a58 <exit at plt>
400f3b: 48 8b 05 de 21 20 00 mov 0x2021de(%rip),%rax #
603120 <page>
400f42: c7 80 78 06 00 00 2a movl $0x2a,0x678(%rax)
400f49: 00 00 00
400f4c: bf 24 1c 40 00 mov $0x401c24,%edi
400f51: e8 e2 fa ff ff callq 400a38 <puts at plt>
400f56: 31 ff xor %edi,%edi
400f58: e8 fb fa ff ff callq 400a58 <exit at plt>
400f5d: 31 c0 xor %eax,%eax
400f5f: 48 81 c4 98 00 00 00 add $0x98,%rsp
400f66: 5b pop %rbx
400f67: 5d pop %rbp
400f68: c3 retq
400f69: e8 aa fa ff ff callq 400a18 <abort at plt>
===============================================================================
Here you can see, the entry 0x401a08[4] - which is used when setjmp's return
value is 3, is 0x400f69, which is the 'default:' case. You can see that the
compiler eliminated this part of the switch statement:
case 3:
*(volatile int *) 0 = 42;
break;
This may be valid for ISO C 99 programs (because a NULL pointer access is
invalid in ISO C 99), but in a POSIX program it is not valid to remove this
- because the program may rely on the fact that a signal handler is called.
Which is the case here.
---------------------
The problem is the same with clang version 2.0 (trunk 105896).
--
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.
More information about the llvm-bugs
mailing list