Is infinite loop still undefined behavior in C++ if it calls shared library?
Asked Answered
D

2

22

It's said that infinite loop for(;;); is undefined behavior.


From http://en.cppreference.com/w/cpp/language/memory_model

In a valid C++ program, every thread eventually does one of the following:

  • terminate
  • makes a call to an I/O library function
  • reads or modifies a volatile object
  • performs an atomic operation or a synchronization operation

No thread of execution can execute forever without performing any of these observable behaviors.

Note that it means that a program with endless recursion or endless loop (whether implemented as a for-statement or by looping goto or otherwise) has undefined behavior.


But what if it calls a function in shared library?

for(;;) sofunc();

The function could do any kind of blocking I/O, or throw exception.

In this case, does the compiler assume that the loop has some observable behaviors?

Deterioration answered 25/12, 2016 at 11:26 Comment(16)
if sofunc doesn't do one of the specified operations, you have invalid program.Janina
I don't know any compiler, OS or CPU that cause any trouble by either using empty non ending loop or non ending loop that calls a function. outside the standard world this question is ridiculous. I have no claims for the OP,I just think this is not a real issueAgitate
But isn't CALL an atomic instruction?Dockage
@DavidHaim -- undefined behavior means only that the language definition doesn't tell you what I he program should do. It's not ridiculous to ask about the limits that apply.Cytokinesis
Compilers are not required to detect undefined behavior.Prizefight
I would say the conclusion is incorrect. It is surely only UB if the program loops indefinitely without hitting one of the four actions lists.Palp
A function call may not be an atomic operation and depends on the architecture of the processor, as well as the parameter count. Look at the assembly count. For example, a common method is to load parameters into registers then perform a "call" instruction. The "call" instruction may cause the processor to reload its instruction cache or pipeline. I don't see how this process can be atomic.Slosh
An infinite loop is well defined behavior. Transferring execution to a function and returning is well defined behavior.Slosh
The compiler can only determine the behavior of the loop based on the declaration of the function. If the function is not within the same translation unit, the compiler cannot determine any behaviors of an external function. The linker is primarily involved in resolving symbols and maybe generation of machine code. Most linkers do not analyze code in libraries, but uses them. Operating Systems may have the responsibility of managing calls to dynamic libraries (such as loading them into memory if necessary).Slosh
Shared libraries are not covered by the standard, so the standard says nothing about them.Thurlow
An implementation, without being able to see the body of sofunc, can assume that it will eventually make some progress. This allows the implementation, in principle, e.g. to stop all other threads and wait until such progress is actually made.Excretion
@DavidHaim we have an example here in C Compilers Disprove Fermat’s Last Theorem. We have many examples of UB that get optimized in odd places for example this case and this case show some surprising optimizations. Is uninitialized local variable the fastest random number generator? for an example of the dangers of inconsistent or morphing optimizations wrt to UB.Alberthaalberti
@DavidHaim also see Compilers and Termination Revisited for a list of compilers known not to preserve infinite loops.Alberthaalberti
See related question: Optimizing away a “while(1);” in C++0x, some of the comments are relevant here. Also see the C version of the question.Alberthaalberti
Distantly similar Why is a fork() call not optimized away in an infinite loop?Presumptive
The last paragraph of the quote is poorly worded IMO; an endless loop does not have UB if the loop also produces observable behaviourPunctilious
S
18

There are a number of places where the language of the Standard gives compilers freedoms beyond what are required for useful optimizations, but which would instead provide compilers with ways to throw the Principle of Least Astonishment out the window. The way the rules about endless loops are written fits that category.

Most of the optimizations which would be facilitated by the rules about endless loops would be enabled by language which specified that the time required to execute a section of code, even if infinite, is not considered to be a side-effect that compilers are required to preserve. Such a rule would allow a compiler to omit any loop iterations which don't have any direct side-effects and don't modify values that are used elsewhere.

The Standard, however, goes beyond that. Given the code:

int foo(void)
{
  int x=0;
  do
  {
    x=functionWithNoSideEffects(x);
  } while(x != 23 && x != 42);
  return x;
}

a compiler that could show that functionWithNoSideEffects would never have any defined side-effects and would never return 23 could replace the code for "foo" with "return 42;". Even if the purpose of the program was to test whether functionWithNoSideEffects would ever return 42 (in which case having the generated code return 42 whether the function does or not would be unhelpful) the Standard would not require compilers to generate code to actually test that unless the loop included some kind of "side-effect".

I'm not personally convinced that the value of having a rule that says that if compilers can show that a loop can't terminate without X being true, they may regard X as being true whether or not there's any means by which it could be. Optimizations based on that principle seem popular, however.

Suburban answered 25/12, 2016 at 20:35 Comment(3)
Why 23? Shouldn't it be 42?Soult
@wallyk: I tweaked the example to make it a little more interesting. Do you like that better?Suburban
Definitely an improvement. But I thought there was only one answer.Soult
O
-1

Yes it is, if the library is written in C++. Otherwise the combination is not a (pure) C++ program anymore and can’t be governed by the C++ standard alone.

IOW, if during or after the dynamic linking it is somehow known that 1) the combination is a C++ program, and 2) sofunc has no side effects, then it can let the nasal demons fly.

Orelu answered 28/9, 2021 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.