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

            Bug ID: 91475
           Summary: Optimization causes infinite loop
           Product: gcc
           Version: 9.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: eric_musser at yahoo dot com
  Target Milestone: ---

The following code on x86-64 9.2.0 compiled with:

gcc -Wall -O2

unexpectedly produces wrong output and an infinite loop:

#include <stdio.h>
#include <iostream>

int main(int argc, char** argv) {
    char buf[50];
    for (int j = 0; j < 9; ++j) {
      std::cout << (j * 0x20000001) << " " << j << std::endl;
      sprintf(buf, "%d", j);
    }
    return 0;
}

Output (truncated) is:
0 0

536870913 1
1073741826 2
1610612739 3
-2147483644 4
-1610612731 5
-1073741818 6
-536870905 7
8 8
536870921 9
1073741834 10
1610612747 11
-2147483636 12
-1610612723 13
...

The sprintf is present only to prevent the loop from being unrolled (and the
issue doesn't occur). The issue appears to because the code is being optimized
roughly as:

int main(int argc, char** argv) {
    char buf[50];
    for (int j = 0, running_j = 0; running_j != 9 * 0x20000001LL ; running_j +=
0x20000001, ++j) {
      std::cout << running_j << " " << j << std::endl;
      sprintf(buf, "%d", j);
    }
    return 0;
}


It loops because running_j is int32 and cannot possibly equal the pre-computed
total. The optimizer actually detects this and removes the end condition of the
for loop completely.

I realize the code is invoking undefined behavior because of signed overflow
with j * 0x20000001LL but it seems either the compiler should error/warning
because of this or the for loop optimization should not happen. Without, the
sprintf I do see a warning of undefined behavior (in loop iteration 4).

I see other bugs similar to this but this is the only I see with a hardcoded
constant as the end condition of the for loop.

Reply via email to