[Bug c++/91475] Optimization causes infinite loop

2019-08-16 Thread eric_musser at yahoo dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91475

--- Comment #2 from Eric Musser  ---
But in this case the undefineness is not directly related to the for loop.
Further the optimizer that changes the loop to maintain and compare j *
0x2001 as opposed to just j could detect certain overflow as the upperbound
for the loop is a constant (j < 9) -- since 9 * 0x2001 > (1<<31). In this
case the optimization could either be disabled or produce a warning. The fact
the end-condition of the for loop is optimized away completely suggests this is
not a runtime issue (the infinite loop is hardcoded into resulting assembly).

In the case the upperbound of the for loop is variable I agree it is not
possible to detect nor may it be worth disabling the optimization if there is
only a chance of overflow.

[Bug c++/91475] New: Optimization causes infinite loop

2019-08-16 Thread eric_musser at yahoo dot com
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 
#include 

int main(int argc, char** argv) {
char buf[50];
for (int j = 0; j < 9; ++j) {
  std::cout << (j * 0x2001) << " " << 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 * 0x2001LL ; running_j +=
0x2001, ++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 * 0x2001LL 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.