https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120578

            Bug ID: 120578
           Summary: Loop termination check eliminated under -O2/-O3/Os
                    when int overflow occurs
           Product: gcc
           Version: 15.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 2023091106 at cauc dot edu.cn
  Target Milestone: ---

in gcc11/12/13/14/15,When using optimization flags such as -O2, -O3, or -Os,
the program may fall into an infinite loop. Upon inspecting the generated
assembly code, the cmp and jl (compare and jump) instructions are missing,
indicating that the condition i < 10 has been optimized away by the compiler.

However, adding a branch like if (i == 2), or changing value += i * k to value
+= (long long)i * k, causes the program to execute correctly. This suggests
that under these optimization levels, GCC performs early evaluation of
arithmetic expressions and assumes int as the default type.

This behavior results in the for loop’s termination condition being affected by
internal computations, violating the Semantic Preservation Principle. Until a
more appropriate constraint relationship is established, such optimizations
should be avoided, especially when internal calculations can interfere with
loop bounds.
========the gcc code========
#include <stdio.h>
#include <stdlib.h>

int main() {
    int value=0;
    int k = 1024*1024*1024;

    for (int i = 0; i < 10; i++) {
        if (i == 3){ // when set if (i ==2), the code will work normal
            break;
        }
        value += i * k;
        printf("i: %d\n", i);
    }
    return value;
}

========the gcc output========
when use -O2/O3/Os, the code won't stop

$ gcc -Wall -Wextra -O0 -o test test.c
$ ./test
i: 0
i: 1
i: 2


$ gcc-14 -Wall -Wextra -O2 -o test test.c
$ ./test 
i: 0
i: 1
i: 2
i: 3
...

========the gcc versions=========
$ gcc-14 -v
Using built-in specs.
COLLECT_GCC=gcc-14
COLLECT_LTO_WRAPPER=/opt/gcc-14/libexec/gcc/x86_64-pc-linux-gnu/14.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/opt/gcc-14 --enable-languages=c,c++
--disable-multilib
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 14.1.0 (GCC)

========the assembly code=========
when use -O2/O3/Os, the cmp and jl (compare and jump) instructions are missing
$in -O0

.LC0:
        .string "i: %d\n"
main:
        push    rbx
        mov     ebx, 0
.L2:
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        add     ebx, 1
        cmp     ebx, 3
        je      .L4
        cmp     ebx, 9
        jle     .L2
.L4:
        mov     eax, 0
        pop     rbx
        ret


$in -O2
.LC0:
        .string "i: %d\n"
main:
        push    rbx
        xor     ebx, ebx
.L2:
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        add     ebx, 1
        call    printf
        jmp     .L2

Reply via email to