1

Here i have very simple program:

#include <iostream>

int main()
{
  while(1);
}

void unreal() {
  std::cout << "Hello world!" << std::endl;
}

For some reason if unreal fucntion placed after main, compiled program prints "Hello word", despite the fact that unreal fucntion never called explicitly. Why does this happen? Is it just consequences of optimizations and undefined behavior caused by them?

Compiled with:

clang++17 loop.cpp -O1 -o loop

clang++-17 --version
Ubuntu clang version 17.0.0 (++20230510031624+e5532fb4935b-1~exp1~20230510151722.922)
Target: x86_64-pc-linux-gnu
Thread model: posix
toozyfuzzy
  • 1,080
  • 1
  • 9
  • 20
  • 1
    `while(1);` is UB... Anything can happen. – Jarod42 Jul 13 '23 at 11:47
  • I believe the duplicate answer your question, if not then please describe what is missing and we can reopen the question. – Quimby Jul 13 '23 at 11:48
  • 2
    C++ has made infinite loops undefined behavior to be able to do optimizations : [N1528: Why undefined behavior for infinite loops?](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm). So any code that has a while loop without side effects is in fact an illformed C++ program. And this proves not all programs that compile are correct programs. – Pepijn Kramer Jul 13 '23 at 11:49
  • You include iostream, which is defined (in the standardese sense) to inject global objects into the TU, along with dynamic initialization. Clang may assume this dynamic initialization in fact end with the program aborting (because infinite loops are a constraint violation, so the code in main must never be executed). And since the object's initialization can in fact do *anything*, it may as well call that function you defined, as far as Clang cares.... – StoryTeller - Unslander Monica Jul 13 '23 at 11:52
  • Let me fix that first line for you: "Here i have very simple **ill-defined** program:" – Eljay Jul 13 '23 at 11:59
  • @PepijnKramer Just noticing: Such infinite loops have been used on micro-controllers to stop execution in error case (if the MPU didn't support some kind of specific 'halt' command...) – not possible any more now (though we could simply write to some volatile dummy variable to fix), at least without compiler extensions ;) – Aconcagua Jul 13 '23 at 12:21
  • The [assembly code](https://godbolt.org/z/9hWhq3zPT) generated by clang does in deed produce code that ends up in the `unreal` function. Yes, it's UB, but still surprising. BTW, gcc does generate the infinite loop. The behaviour of clang seemed to have changed with version 13.0.0, before it also generated the infinite loop. BTW, if you change `void unreal()` to `static void unreal()`, the assembly output is surprising, check it out. – Jabberwocky Jul 13 '23 at 13:55
  • @Aconcagua Hehe I didn't know that but reading or writing a volatile is a (minimal) side effect which cannot be optimized out. Somehow to me reading would even feel like less optimizable ;) – Pepijn Kramer Jul 13 '23 at 15:21

0 Answers0