clang generates incorrect gcov code when using -mno-red-zone flag

Originator:phil
Number:rdar://12843084 Date Originated:09-Dec-2012 08:55 PM
Status:Closed Resolved:19-Jun-2013
Product:Developer Tools Product Version:4.6
Classification:Serious Bug Reproducible:Always
 
Summary:
When compiling code with clang's -fprofile-arcs -ftest-coverage flags, the code generated for the automatically generated helper function __llvm_gcov_indirect_counter_increment ignores the -mno-red-zone flag.


Steps to Reproduce:

1. Create a source file redzone.c with the following content:

// BEGIN redzone.c
int hello(int a)
{
        switch (a % 2)
        {
        case 0:
                ++a;
        case 1:
                a /= 2;
        }
        return a;
}
// END redzone.c

The exact content of the file is not of much relevance, we just need to get the compiler to generate a __llvm_gcov_indirect_counter_increment function.


2. Compile it using this command:

/Applications/Xcode46-DP3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -O0  -mno-red-zone -fprofile-arcs -ftest-coverage redzone.c -c

3. Inspect the disassembly of the function __llvm_gcov_indirect_counter_increment using the command:

otool -tV redzone.o -p ___llvm_gcov_indirect_counter_increment |less


Expected Results:
Due to the -mno-red-zone flag, no data should be stored below the %rsp stack pointer in the disassembly.

Actual Results:
The code uses 24 bytes of the red zone:

___llvm_gcov_indirect_counter_increment:
00000000000000f0        pushq   %rbp
00000000000000f1        movq    %rsp,%rbp ; note rsp is the same as rbp
00000000000000f4        movl    (%rdi),%eax
00000000000000f6        cmpl    $0xffffffff,%eax
00000000000000fb        movq    %rsi,0xf8(%rbp)  ; RED ZONE
00000000000000ff        movl    %eax,0xf4(%rbp)  ; RED ZONE
0000000000000102        je      0x00000137
0000000000000108        movl    0xf4(%rbp),%eax  ; RED ZONE
000000000000010b        movl    %eax,%ecx
000000000000010d        movq    0xf8(%rbp),%rdx  ; RED ZONE
0000000000000111        movq    (%rdx,%rcx,8),%rcx
0000000000000115        cmpq    $_hello,%rcx
000000000000011c        movq    %rcx,0xe8(%rbp)  ; RED ZONE
0000000000000120        je      0x00000137
0000000000000126        movq    0xe8(%rbp),%rax  ; RED ZONE
000000000000012a        movq    (%rax),%rcx
000000000000012d        addq    $0x00000001,%rcx
0000000000000134        movq    %rcx,(%rax)
0000000000000137        popq    %rbp
0000000000000138        ret
0000000000000139        nopl    _hello(%rax)

When running in an environment with no red zone on the stack, such as the OSX kernel, this code ends up crashing due to corruption of the pointers stored beyond the top of the stack.


Regression:
The versions of clang in the 4.5 Developer Tools and earlier do not exhibit this fault, although in the previous version the function was not generated as a local symbol.

Notes:
The generated function __llvm_gcov_init also appears to be affected, although it's less likely to cause a crash in that case, as it's so rarely executed. Other functions may also be affected?

Clang version:
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix


19-Feb-2013 06:14 PM Phillip Jordan:
The machine code generated by the compiler in the release version of the 4.6 developer tools is identical and thus still invalid.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!