28

In C++11, as an infinite loop with no side-effects, the following program is UB:

int main() {
   while (true) {}
}

Is the following also UB?

void foo() {
   foo();
}

int main() {
   foo();
}

Citations from the standard for both programs would be ideal.

Xeo
  • 123,374
  • 44
  • 277
  • 381
Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989

2 Answers2

24

It's UB because it's not worded in terms of loops, but in terms of (1.10p24):

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.

This applies to both, as opposed to the more older formulation in one of the C++0x drafts. (See this question for discussions).

Note that disregarding of that, the behavior can easily be undefined if the recursion exceeds the implementation limit of the number of nested recursive function calls. That has always been the case.

Community
  • 1
  • 1
Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175
  • Does this mean that my clarification "with no side effects" is an inaccurate one? – Lightness Races in Orbit May 05 '11 at 23:27
  • Oh, and is the implication sound that the application's "base thread" is one of the "any thread[s]" that the clause refers to? Or could it simply be referring to spawned child threads? – Lightness Races in Orbit May 05 '11 at 23:28
  • 1
    @Tomalak ah I think i finally know the precise meaning of the above text. It means, at any point, it may assume that the implementation does one of those things (if the program terminates, the condition is full-filled, for example). So `volatile int a = 0; while(1);` is UB; because the program never again does one of the 4 bullet-point things. – Johannes Schaub - litb May 05 '11 at 23:38
  • @litb: Right; makes sense. Seems a bit ambiguous, though. – Lightness Races in Orbit May 05 '11 at 23:39
  • @Tomalak I would think the thread that has `main` executed is a thread too. The spec says "The execution of the entire program consists of an execution of all of its threads.". So for `int main() { }`, the `main` function executes, so by the above paragraph, since *something* executes, the `main` function executes in a thread, I think! – Johannes Schaub - litb May 05 '11 at 23:40
  • 1
    @Tomalak I can't think of any example where an infinite loop without side effects would satisfy one of the above 4 bullets. But I've not looked up where the spec says or where it follows from that performing a synchronization operation or an atomic operation is a side effect. – Johannes Schaub - litb May 05 '11 at 23:46
  • This does not imply UB. Note ISO C++ has no rule equivalent to Clause 4p2 in ISO C. – FrankHB Dec 01 '17 at 04:40
  • @FrankHB i don't understand. Do you say that the program terminates? Do you also say that the program has a finite number of nested recursive function calls? – Johannes Schaub - litb Dec 02 '17 at 16:54
  • It depends on the implementation. There is no guarantee that the program will or will not terminate. This still does not mean it incurs UB which voids any predictable guarantee (not only about termination). – FrankHB Dec 16 '17 at 16:35
1

I don't think the standard says the behavior is undefined, it just says a loop that has no side effects may be assumed to eventually terminate.

So:

int main() {
   while (true) {}
}

May terminate or loop forever.

void foo() {
   foo();
}

int main() {
   foo();
}

May also terminate, loop forever, or possibly run out of stack space (if the compiler does not implement tail recursion).

I don't think either have any right to do anything other than listed, so I don't think the behavior is completely "undefined".

Clinton
  • 20,364
  • 13
  • 59
  • 142
  • 1
    Surely if an assumption is made and the program does not satisfy the assumption, then the program's behaviour is undefined by definition? – Lightness Races in Orbit May 06 '11 at 09:37
  • 1
    This means that the _implementation_ may assume that a program will not have code that will not eventually terminate. This means that no valid programs shall have code that does not eventually terminate (or satisfy the other requirements in 1.10/24). This isn't the same as "you can do this, as long as you (the user) assume that your loop might just stop on its own one day". – Lightness Races in Orbit Jul 17 '11 at 21:14
  • It means something more like, "eating up CPU cycles is not a side effect". Code that has no side effects other than CPU usage, and does not produce a value that is used later, need not run at all. The implementation is free to decide whether to run that code or not. It does not, however, get to order pizza. – cHao Aug 28 '13 at 12:47