MikeMirzayanov's blog

By MikeMirzayanov, history, 8 years ago, translation, In English

Hi!

I know that it will be obvious for real C++-masters, but for me it is small surprise. I used to think that signed overflow in C ++ does not cause real undefined behavior on a particular platform. That is, it is clear that depending on the big-endianness/little-endian result may be different.

I found short and funny example:

#include <iostream>
int main()
{
    for (int i = 0; i < 300; i++)
        std::cout << i << " " << i * 12345678 << std::endl;
}

Being compiled with -O2 on modern g++ it will run infinitely. Suddenly, right?

Tags g++, ub
  • Vote: I like it
  • +257
  • Vote: I do not like it

»
8 years ago, # |
Rev. 2   Vote: I like it +22 Vote: I do not like it

Last sentence is written in russian, on eng interface :(

»
8 years ago, # |
  Vote: I like it +1 Vote: I do not like it

This is so strange! I tested it on my machine, and it does indeed run infinitely.

It's interesting I believe. Why does that happen?

  • »
    »
    8 years ago, # ^ |
    Rev. 2   Vote: I like it +117 Vote: I do not like it

    There is russian explanation from yeputons, so I am just translating:

    -Waggresive-loop-optimization option is turned on by -O2,

    Optimizer infers that because i*12345678 should never overflow, i will never be higher then 173, which means that i < 300 is always true, so it replaces condition "i < 300" with true.

    • »
      »
      »
      8 years ago, # ^ |
        Vote: I like it +52 Vote: I do not like it

      strange, if you replace endl with '\n' , the code no longer runs infinitely

      • »
        »
        »
        »
        8 years ago, # ^ |
          Vote: I like it +10 Vote: I do not like it

        My take on this is that std::endl flushes cache, so the output operation happens in the cycle, so output is produced within the cycle and is expected to conform to language rules, which means no overflow is expected and optimization works.

        If do you "\n", cache is flushed after the cycle ends, so there is no external output within the cycle, which somehow turns off optimization.

        Strange indeed. It probably takes a guy from g++ development team to tell exactly what happens.

»
8 years ago, # |
  Vote: I like it +23 Vote: I do not like it

By the way, it looks like it's possible to disable that behavior in GCC with a special key: -fno-strict-overflow

»
8 years ago, # |
  Vote: I like it +24 Vote: I do not like it

And sometimes such advanced optimizations even lead to vulnerabilities: http://lwn.net/Articles/342330/

»
8 years ago, # |
Rev. 3   Vote: I like it +5 Vote: I do not like it

I used "\n" instead of endl and got this:

a.cpp: In function ‘int main()’:
a.cpp:5:38: warning: iteration 174u invokes undefined behavior [-Waggressive-loop-optimizations]
         std::cout << i << " " << i * 12345678 << "\n";
                                      ^
a.cpp:4:5: note: containing loop
     for (int i = 0; i < 300; i++)
  • »
    »
    8 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    Then this must me a warning bug. Initially whan I was reading this post I thought that gcc does not produce any warnings about that, but it is not good that warning is produced in one case and is not produced in another case.

    • »
      »
      »
      8 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      I confirmed the difference in warning reporting between std::endl and "\n" with GCC 4.8.1 and 4.8.2 . The bug seems to be fixed in GCC >= 4.9.0, I couldn't test if the fix is included in GCC 4.8.3 — 4.8.5 .

      • »
        »
        »
        »
        8 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Mine: gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

»
8 years ago, # |
  Vote: I like it 0 Vote: I do not like it

This is another example of breaking the code with higher optimization when the code is not completely correct, Nicely explained as well. http://stackoverflow.com/questions/36626810/g-optimization-breaks-for-loops