Clang generates llvm intermediate code with an endless loop, when -O is used. Here is source .c code: $ cat test.c #include <wchar.h> int main () { return btowc ('\0'); } And after compilation we have: (gdb) disas main Dump of assembler code for function main: 0x00000000004004f0 <+0>: jmp 0x4004f0 <main> End of assembler dump. Here is LLVM IR: $ clang -S -emit-llvm test.c; cat test.s ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-pc-linux-gnu" define i32 @main() nounwind { %1 = alloca i32, align 4 store i32 0, i32* %1 %2 = call i32 @btowc(i32 0) nounwind ret i32 %2 } declare i32 @btowc(i32) nounwind $ clang -O -S -emit-llvm test.c; cat test.s ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-pc-linux-gnu" define i32 @main() nounwind readnone { br label %tailrecurse.i tailrecurse.i: ; preds = %tailrecurse.i, %0 br label %tailrecurse.i } I've attached wchar.h just in case.
Created attachment 6391 [details] glibc wchar.h
Testcase boils down to something like the following: typedef __typeof(+L'a') wint_t; extern wint_t __btowc_alias (int __c) __asm ("btowc"); __attribute((nothrow)) inline wint_t btowc (int __c) { return __btowc_alias (__c); } int f(int x) { return btowc(x); } clang resolves the call to __btowc_alias into a call to btowc, so clang essentially sees through the trick to try and make the inline version call the out-of-line version. The function then ends up looking like it's tail-recursive, i.e. an infinite loop.
I've found another test case with realpath. extern char *__realpath_alias (__const char *__restrict __name, char *__restrict __resolved) __asm__ ("" "realpath"); extern char * realpath (__const char *__restrict __name, char *__restrict __resolved) { return __realpath_alias (__name, __resolved); } char *f(const char *path, char *buf) { return realpath(path, buf); }
*** Bug 10179 has been marked as a duplicate of this bug. ***
*** Bug 10207 has been marked as a duplicate of this bug. ***
I get an infinite loop for btowc() with -O2 but not -O1 as described in bug #10207. This bug appears to have quite far reaching consequences. Not only does it make the configure scripts of such software as gnu tar, coreutils, diffutils, findutils, gettext, and grep hang. It might be the reason gnu sed, and awk hang during their tests as well (at least they hang when compiled with -O2 but not with -O1).
*** Bug 10981 has been marked as a duplicate of this bug. ***
*** Bug 10160 has been marked as a duplicate of this bug. ***
Another testcase with getcwd, boils down to (after preprocessing, removing impossible code paths, etc) typedef __typeof__(sizeof(int)) size_t; extern char *__getcwd_alias (char *__buf, size_t __size) __asm__ ("" "getcwd"); extern char *getcwd (char *__buf, size_t __size) { return __getcwd_alias (__buf, __size); } char *test(char *buf, int len) { return getcwd((char *)buf, len); } This bug clang build a hanging vim on Linux unless optimizations are explicitly disabled.
(In reply to comment #9) > Another testcase with getcwd, boils down to (after preprocessing, removing > impossible code paths, etc) > > typedef __typeof__(sizeof(int)) size_t; > extern char *__getcwd_alias (char *__buf, size_t __size) __asm__ ("" "getcwd"); > extern char *getcwd (char *__buf, size_t __size) > { > return __getcwd_alias (__buf, __size); > } > char *test(char *buf, int len) > { > return getcwd((char *)buf, len); > } > > This bug clang build a hanging vim on Linux unless optimizations are explicitly > disabled. s/clang/causes clang to/
Dragonegg turns this into define i32 @btowc(i32 %__c) nounwind uwtable inlinehint { entry: %0 = tail call i32 @"\01btowc"(i32 %__c) nounwind ret i32 %0 } declare i32 @"\01btowc"(i32) define i32 @f(i32 %x) nounwind uwtable { entry: %0 = tail call i32 @"\01btowc"(i32 %x) nounwind ret i32 %0 } which results in f being codegened as jmp btowc
Is this still a problem for clang? This is what I'm getting now: $ cat test.c #include <wchar.h> int main () { return btowc ('\0'); } $ clang test.c -o - -S -emit-llvm -O ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.7.2" define i32 @main() nounwind uwtable ssp { entry: %call = tail call i32 @btowc(i32 0) nounwind ret i32 %call } declare i32 @btowc(i32) $ cat > test.c typedef __typeof(+L'a') wint_t; extern wint_t __btowc_alias (int __c) __asm ("btowc"); __attribute((nothrow)) inline wint_t btowc (int __c) { return __btowc_alias (__c); } int f(int x) { return btowc(x); } $ clang test.c -o - -S -emit-llvm -O ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.7.2" define i32 @f(i32 %x) nounwind uwtable ssp { entry: %call.i = tail call i32 @"\01btowc"(i32 %x) nounwind ret i32 %call.i } declare i32 @"\01btowc"(i32) $ cat > test.c extern char *__realpath_alias (__const char *__restrict __name, char *__restrict __resolved) __asm__ ("" "realpath"); extern char * realpath (__const char *__restrict __name, char *__restrict __resolved) { return __realpath_alias (__name, __resolved); } char *f(const char *path, char *buf) { return realpath(path, buf); } $ clang test.c -o - -S -emit-llvm -O ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.7.2" define i8* @realpath(i8* noalias %__name, i8* noalias %__resolved) nounwind uwtable ssp { entry: %call = tail call i8* @"\01realpath"(i8* %__name, i8* %__resolved) nounwind ret i8* %call } declare i8* @"\01realpath"(i8*, i8*) define i8* @f(i8* %path, i8* %buf) nounwind uwtable ssp { entry: %call.i = tail call i8* @"\01realpath"(i8* %path, i8* %buf) nounwind ret i8* %call.i } $ cat > test.c typedef __typeof__(sizeof(int)) size_t; extern char *__getcwd_alias (char *__buf, size_t __size) __asm__ ("" "getcwd"); extern char *getcwd (char *__buf, size_t __size) { return __getcwd_alias (__buf, __size); } char *test(char *buf, int len) { return getcwd((char *)buf, len); } $ clang test.c -o - -S -O -emit-llvm ; ModuleID = 'test.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.7.2" define i8* @getcwd(i8* %__buf, i64 %__size) nounwind uwtable ssp { entry: %call = tail call i8* @"\01getcwd"(i8* %__buf, i64 %__size) nounwind ret i8* %call } declare i8* @"\01getcwd"(i8*, i64) define i8* @test(i8* %buf, i32 %len) nounwind uwtable ssp { entry: %conv = sext i32 %len to i64 %call.i = tail call i8* @"\01getcwd"(i8* %buf, i64 %conv) nounwind ret i8* %call.i }
(In reply to comment #12) > Is this still a problem for clang? This is what I'm getting now: Still reproducable on Linux with [/kutu/stuff]> clang -v SUSE Linux clang version 3.0 (branches/release_30 142341) (based on LLVM 3.0) Target: x86_64-unknown-linux-gnu Thread model: posix And AFAIK it only affects Linux.
(In reply to comment #13) > (In reply to comment #12) > > Is this still a problem for clang? This is what I'm getting now: > > Still reproducable on Linux with > > [/kutu/stuff]> clang -v > SUSE Linux clang version 3.0 (branches/release_30 142341) (based on LLVM 3.0) > Target: x86_64-unknown-linux-gnu > Thread model: posix > > And AFAIK it only affects Linux. Interesting. When I took your IR example from the fist comment and ran it through 'opt' it generated IR which looked just fine. And the result was a 'jmp btowc' command, like Duncan's. Can you investigate further? I don't have easy access to a Linux box..
I can only reproduce the problem with my original testcase from bug 10160 , http://llvm.org/bugs/attachment.cgi?id=6754
(In reply to comment #14) > Interesting. When I took your IR example from the fist comment and ran it > through 'opt' it generated IR which looked just fine. And the result was a 'jmp > btowc' command, like Duncan's. > > Can you investigate further? I don't have easy access to a Linux box.. I just remembered that I *do* have access to a Linux box. All of the tests I ran give the result as "ret i8* undef" (or some variation on that) with `-O'. Almost certainly not what you're looking for.
(In reply to comment #16) > (In reply to comment #14) > > Interesting. When I took your IR example from the fist comment and ran it > > through 'opt' it generated IR which looked just fine. And the result was a 'jmp > > btowc' command, like Duncan's. > > > > Can you investigate further? I don't have easy access to a Linux box.. > > I just remembered that I *do* have access to a Linux box. All of the tests I > ran give the result as "ret i8* undef" (or some variation on that) with `-O'. > Almost certainly not what you're looking for. Yes, please try with http://llvm.org/bugs/attachment.cgi?id=6754 and you need to do clang -O2 -D_FORTIFY_SOURCE=2 mmap.c since the definition of _FORTIFY_SOURCE=2 along with -O2 triggers the problem. bug 10160 had a nicer discussion of this bug but its marked as a duplicate :(
Another reduced testcase for which clang, when passed -D_FORTIFY_SOURCE=2, turns into an infinite loop, on current 64-bit Debian testing, in both 64-bit and 32-bit mode: $ cat bug.c #include <stdint.h> #include <stdio.h> int fread_n_bytes(FILE * f, int n, uint8_t *s) { int i; if (s == NULL) for (i = 0; i < n; i++) fgetc(f); else if(fread(s, 1, n, f) < (size_t)n) // infinite loop here. return -1; return 0; } int main(int argc, char * argv[]) { uint8_t buf[8]; return fread_n_bytes((FILE *)0x12345678, 8, buf); } clang invocations that produce bad programs: $ clang -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o bad1 bug.c $ clang -m32 -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o bad2 bug.c $ clang -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -o bad3 bug.c Invocations that produce good programs: $ clang -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -o good1 bug.c $ clang -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o good2 bug.c $ gdb bad1 GNU gdb (GDB) 7.3-debian Copyright (C) 2011 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/a515273/essai_clang/bad1...done. (gdb) run Starting program: /home/a515273/essai_clang/bad1 ^C Program received signal SIGINT, Interrupt. fread_n_bytes (f=<optimized out>, n=<optimized out>, s=<optimized out>) at bug.c:12 12 if(fread(s, 1, n, f) < (size_t)n) (gdb) bt #0 fread_n_bytes (f=<optimized out>, n=<optimized out>, s=<optimized out>) at bug.c:12 #1 0x00000000004005cf in main (argc=<optimized out>, argv=<optimized out>) at bug.c:20 (gdb) disassemble Dump of assembler code for function fread_n_bytes: 0x0000000000400554 <+0>: push %rbp 0x0000000000400555 <+1>: mov %rsp,%rbp 0x0000000000400558 <+4>: push %r14 0x000000000040055a <+6>: push %rbx 0x000000000040055b <+7>: sub $0x10,%rsp 0x000000000040055f <+11>: mov %esi,%ebx 0x0000000000400561 <+13>: mov %rdi,%r14 0x0000000000400564 <+16>: mov %fs:0x28,%rax 0x000000000040056d <+25>: mov %rax,-0x18(%rbp) 0x0000000000400571 <+29>: test %rdx,%rdx 0x0000000000400574 <+32>: jne 0x40059a <fread_n_bytes+70> 0x0000000000400576 <+34>: test %ebx,%ebx 0x0000000000400578 <+36>: jle 0x400586 <fread_n_bytes+50> 0x000000000040057a <+38>: mov %r14,%rdi 0x000000000040057d <+41>: callq 0x400450 <fgetc@plt> 0x0000000000400582 <+46>: dec %ebx 0x0000000000400584 <+48>: jne 0x40057a <fread_n_bytes+38> 0x0000000000400586 <+50>: mov %fs:0x28,%rax 0x000000000040058f <+59>: cmp -0x18(%rbp),%rax 0x0000000000400593 <+63>: je 0x40059c <fread_n_bytes+72> 0x0000000000400595 <+65>: callq 0x400440 <__stack_chk_fail@plt> => 0x000000000040059a <+70>: jmp 0x40059a <fread_n_bytes+70> 0x000000000040059c <+72>: xor %eax,%eax 0x000000000040059e <+74>: add $0x10,%rsp 0x00000000004005a2 <+78>: pop %rbx 0x00000000004005a3 <+79>: pop %r14 0x00000000004005a5 <+81>: pop %rbp 0x00000000004005a6 <+82>: retq End of assembler dump.
Looking like the source fortification is necessary? Maybe it's interfering with an optimization that the code expects to happen?
Potential fix here: http://comments.gmane.org/gmane.comp.compilers.clang.scm/40901
Fixed in r143049.
Well, the testcase I posted in comment #18 still fails (infinite loops) for me after r143049, when -D_FORTIFY_SOURCE=2 is used: $ clang --version clang version 3.1 (trunk 143096) Target: x86_64-unknown-linux-gnu Thread model: posix a515273@aofr42198:~/essai_clang$ rm bad* good* a515273@aofr42198:~/essai_clang$ sh build.sh a515273@aofr42198:~/essai_clang$ ls -1 bad1 bad2 bad3 bug.c build.sh good1 good2 $ ./good1 Segmentation fault $ ./good2 Segmentation fault $ ./bad1 ^C $ ./bad2 ^C $ ./bad3 ^C $ cat build.sh #!/bin/sh # The base invocation, reduced from my original testcase. clang -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o bad1 bug.c # It ain't better in 32-bit mode. clang -m32 -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o bad2 bug.c # Disabling stack protector switches doesn't help. clang -D_FORTIFY_SOURCE=2 -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -o bad3 bug.c # Disabling FORTIFY_SOURCE helps. clang -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -o good1 bug.c # No problem if stack protector switches are activated but FORTIFY_SOURCE is not set. clang -Os -g3 -Wall -W -Wno-unused-parameter -Wshadow -Wwrite-strings -Wredundant-decls -Wdeclaration-after-statement -fstack-protector-all -Wstack-protector -o good2 bug.c $ cat bug.c #include <stdint.h> #include <stdio.h> int fread_n_bytes(FILE * f, int n, uint8_t *s) { int i; if (s == NULL) for (i = 0; i < n; i++) fgetc(f); else if(fread(s, 1, n, f) < (size_t)n) return -1; return 0; } int main(int argc, char * argv[]) { uint8_t buf[8]; return fread_n_bytes((FILE *)0x12345678, 8, buf); }
(In reply to comment #21) > Fixed in r143049. Problem is still producable with the testcase from bug 10160 , http://llvm.org/bugs/attachment.cgi?id=6754
Reduced testcase that still fails: extern int foo_alias (void) __asm__ ("foo"); inline __attribute__ ((__always_inline__)) int foo (void) { return foo_alias (); } int bar() { foo(); }
Dragonegg produces this for the testcase in comment 24: define i32 @foo() nounwind uwtable inlinehint alwaysinline { entry: %0 = tail call i32 @"\01foo"() nounwind ret i32 %0 } declare i32 @"\01foo"() define i32 @bar(...) nounwind uwtable { entry: %0 = call i32 @"\01foo"() nounwind ret i32 undef }
fixed in r143222.
(In reply to comment #26) > fixed in r143222. This doesn't apply cleanly to the 3.0 release branch: http://llvm.org/svn/llvm-project/cfe/branches/release_30
With clang r143304, the reduced testcase I posted in comments #18 and #22 now segfaults (which is the expected behaviour) even when compiled with -D_FORTIFY_SOURCE=2, and the original application from which I extracted it doesn't contain an infinite loop anymore, either. Thanks :)
This fix doesn’t work in C++ mode, where the fortify wrappers use __attribute__ ((__always_inline__)) but not __attribute__ ((__gnu_inline__)): http://llvm.org/bugs/show_bug.cgi?id=10276#c9