-22

Considering

C++11 §1.10/24 (in [intro.multithread])

The implementation may assume that any thread will eventually do one of the following:
— terminate,
— make a call to a library I/O function,
— access or modify a volatile object, or
— perform a synchronization operation or an atomic operation.
[Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. —end note ]

… is the compiler allowed to optimize away the following loop:

int main(int argc, char* argv[]) {
    while ( true )
        fork();
}

?

(There is some earlier discussion at (Optimizing away a "while(1);" in C++0x), but it does not seem to answer the case of a fork call in the loop.)

Community
  • 1
  • 1
Ismael R.
  • 107
  • 2
  • 12
    **Moderator Note**: Reverting good edits is frowned upon. If the edit makes the question better, leave it; don't fight over it. If the OP believes it's a bad edit, they'll let us know and revert. Also, if you're interested in discussing this, [we have a meta post for that](http://meta.stackoverflow.com/questions/288802/). – George Stocker Mar 27 '15 at 15:59
  • 6
    The [meta post](http://meta.stackoverflow.com/questions/288802/) mentions that this is a *fork bomb*. Running this program can cause your system to hang. – Keith Thompson Mar 28 '15 at 19:45
  • This question does not seem too broad to me. It essentially asks whether The compiler must assume a call to an `extern` function does one of those 4 things, which is a yes/no answer. – Raedwald Feb 01 '18 at 07:42

1 Answers1

10

fork is a normal function just like other library functions it invokes glibc fork() wrapper rather than invoking system call directly.

A compiler has no way to determine what does this function contain and a conformant compiler should always avoid optimizing this loop away and this would result in fork bomb as referred in one of the comment.

To avoid the consequences, one should avoid the maximum number of processes a user can own.

From man fork

Since version 2.3.3, rather than invoking the kernel's fork() system call, the glibc fork() wrapper that is provided as part of the NPTL threading implementation invokes clone(2) with flags that provide the same effect as the traditional system call. The glibc wrapper invokes any fork handlers that have been established using pthread_atfork(3).

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • 1
    A compiler may optimize calls to functions defined by the C or C++ standard library, as long as the optimizing code behaves the same way. For example, gcc can and will optimize `printf("hello\n")` to `puts("hello")`. `fork()` is defined by POSIX, not by the language standard -- but I'd say that a POSIX-conforming implementation can legally optimize a call to `fork` as long as the resulting code still behaves as specified by POSIX and by the language standard. Whether that applies in this specific case is an interesting question (and I don't have an answer). – Keith Thompson Mar 28 '15 at 19:40
  • @Mohit: Which of the bullets in the quoted C++ standard text is satisfied by the call to `fork()`? I don't find your answer compelling or convincing, I'm afraid! – Lightness Races in Orbit Mar 29 '15 at 04:05
  • @KeithThompson Lightness: Thanks for the valuable comments. When I said **conformant** in my answer my intention was `C++ conformant`. Pre C++11 compilers for sure can not optimize this away. C++11 conformant (not with posix extensions) would see fork as a library call and it can not be optimized away as the observable behavior of this function is unknown to the compiler. All posix suggests is, on invocation of `fork` call, a new process is created which is an exact copy of calling process(immediately/deferred etc not mentioned). If the process does nothing, not creating it may not hurt posix. – Mohit Jain Mar 30 '15 at 05:17
  • I don't think that means it cannot optimise the call away. I think it means it can assume the call abides by the four bullet points. – Lightness Races in Orbit May 15 '15 at 15:02
  • @LightnessRacesinOrbit A non-posix compliant compiler has no way to ensure that fork call doesn't abide the bullet points. (For ex: it doesn't make a call to library IO function) Isn't it? – Mohit Jain May 20 '15 at 05:39
  • @MohitJain: It doesn't need to "ensure" it. It is allowed to assume. I concede that, in practice, implementations almost certainly _don't_ assume, for the reason you give. But this is about what the standard allows, not about what actually happens. Real-life constraints are always going to be _at least_ as strict as the standard requirements... "at least" being the key phrase! – Lightness Races in Orbit May 20 '15 at 10:02
  • @LightnessRacesinOrbit Wow. Thanks for your comment and rectifying my interpretation. This is disturbing, as it allows compilers to eliminate following code `for(;/*ever*/;) checkAndForwardBluetoothQueue();` assuming `checkAndForwardBluetoothQueue` is in a different compilation unit and where it waits for a condition variable (Bullet 4) for finite time, reads/writes a chip buffer using register (Bullet 3) and updates some logs (Bullet 2) and terminates (Bullet 1) if disconnect command is received. – Mohit Jain May 20 '15 at 11:25
  • @LightnessRacesinOrbit: Wait, what? The compiler can eliminate useful I/O code from an infinite loop? Are you sure that's what you mean?! – psmears May 20 '15 at 19:28
  • @MohitJain: No, the compiler *can't* eliminate your `for` loop with `checkAndForwardBluetoothQueue`. The standard says that the compiler may assume that the thread will eventually do one of the four things. Since it has no knowledge of what `checkAndForwardBluetoothQueue` does, it has no way to determine whether or not the function does any of those four things - so it must assume that it does. – psmears May 20 '15 at 19:37
  • @psmears: That is neither what I mean nor what I said. – Lightness Races in Orbit May 21 '15 at 01:21