[llvm-bugs] [Bug 45191] New: clang generates incorrect X86-64 code optimization for integer assignment-comparison

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Mar 12 18:35:07 PDT 2020


https://bugs.llvm.org/show_bug.cgi?id=45191

            Bug ID: 45191
           Summary: clang generates incorrect X86-64 code optimization for
                    integer assignment-comparison
           Product: clang
           Version: 9.0
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: release blocker
          Priority: P
         Component: -New Bugs
          Assignee: unassignedclangbugs at nondot.org
          Reporter: hzhuang at gmail.com
                CC: htmldeveloper at gmail.com, llvm-bugs at lists.llvm.org,
                    neeilans at live.com, richard-llvm at metafoo.co.uk

We've found the following issue in clang 6 through 9, in x86_64 Linux as well
as MacOS. And might have spanned more releases. This happens consistently for
certain source code arrangement when optimization is enabled (-O1 ~ -O3).
Unoptimized code seems to be fine. Since this bug is a contradiction to
C-language's definition and the C source code is a very common way of writing,
I'd consider it a severe bug that has existed for a few years and many programs
may have been impacted without noticing the issue, if the tests haven't covered
the case.

For the short C program below ('volatile' is to prevent optimizer from directly
short-circuiting the while-loop. In real cases the assignment in the loop can
be function calls.):

#include <stdio.h>
#include <stdint.h>

int32_t volatile g_a = 0x7fffffff;
int32_t volatile g_b = 16;

int main()
{
    int32_t overflown = g_a;
    int32_t m;

    while ((m = overflown - g_a) <= 0)
    {
        overflown = g_a + g_b;
        putchar('.');
    }

    printf("m = %d\n", m);
    return 0;
}

If compiled without optimization, e.g., clang-9 -Wall source.c, the resultant
executable runs fine, printing ".m = 16" and exit. But if it is compiled with
optimization, e.g., clang-9 -Wall -O3 source.c, the generated code will loop
forever printing '.'. Disassembly the main function of the optimized code
shows:

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000401140 <+0>:     push   %rbx
   0x0000000000401141 <+1>:     mov    0x2ef1(%rip),%ebx        # 0x404038
<g_a>
   0x0000000000401147 <+7>:     sub    0x2eeb(%rip),%ebx        # 0x404038
<g_a>
   0x000000000040114d <+13>:    jg     0x401175 <main+53>
   0x000000000040114f <+15>:    nop
   0x0000000000401150 <+16>:    mov    0x2ee2(%rip),%ebx        # 0x404038
<g_a>
   0x0000000000401156 <+22>:    add    0x2ee0(%rip),%ebx        # 0x40403c
<g_b>
   0x000000000040115c <+28>:    mov    0x2edd(%rip),%rsi        # 0x404040
<stdout@@GLIBC_2.2.5>
   0x0000000000401163 <+35>:    mov    $0x2e,%edi
   0x0000000000401168 <+40>:    callq  0x401040 <putc at plt>
   0x000000000040116d <+45>:    sub    0x2ec5(%rip),%ebx        # 0x404038
<g_a>
   0x0000000000401173 <+51>:    jle    0x401150 <main+16>
   0x0000000000401175 <+53>:    mov    $0x402004,%edi
   0x000000000040117a <+58>:    mov    %ebx,%esi
   0x000000000040117c <+60>:    xor    %eax,%eax
   0x000000000040117e <+62>:    callq  0x401030 <printf at plt>
   0x0000000000401183 <+67>:    xor    %eax,%eax
   0x0000000000401185 <+69>:    pop    %rbx
   0x0000000000401186 <+70>:    retq
End of assembler dump.
(gdb) q

Apparently after 'sub' (main+7, +45), a 'test %ebx,%ebx' or 'cmp #0,%ebx' is
missing. Therefore the branch instructions uses the result of 'sub' operation
instead of the result of 'sub'.

Code like this is commonly used for integer comparison on the integer-ring,
e.g., timer timeout, TCP Sequence numbers, etc. The impact of this bug is big.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200313/3599f643/attachment.html>


More information about the llvm-bugs mailing list