In many discussions about undefined behavior (UB), the point of view has been put forward that in the mere presence in a program of any construct that has UB in a p
A C compiler is allowed to do anything it likes as soon as a program enters a state via which there is no defined sequence of events which would allow the program to avoid invoking Undefined Behavior at some point in the future (note any loop which does not have any side-effects, and which does not have an exit condition which a compiler would be to required to recognize, invokes Undefined Behavior in and of itself). The compiler's behavior in such cases is bound by the laws of neither time nor causality. In situations where Undefined Behavior occurs in an expression whose result is never used, some compilers won't generate any code for the expression (so it will never "execute") but that won't prevent compilers from using the Undefined Behavior to make other inferences about program behavior.
For example:
void maybe_launch_missiles(void)
{
if (should_launch_missiles())
{
arm_missiles();
if (should_launch_missiles())
launch_missiles();
}
disarm_missiles();
}
int foo(int x)
{
maybe_launch_missiles();
return x<<1;
}
Under the C current C standard, if the compiler could determinate that disarm_missiles()
would always return without terminating but the three other external functions called above might terminate, the most efficient standard-compliant replacement for the statement foo(-1);
(return value ignored) would be should_launch_missiles(); arm_missiles(); should_launch_missiles(); launch_missiles();
.
Program behavior will only be defined if either call to should_launch_missiles()
terminates without returning, if the first call returns non-zero and arm_missiles()
terminates without returning, or if both calls return non-zero and launch_missiles()
terminates without returning. A program which works correctly in those cases will abide by the standard regardless of what it does in any other situation. If returning from maybe_launch_missiles()
would cause Undefined Behavior, compiler would not be required to recognize the possibility that either call to should_launch_missiles()
could return zero.
As a consequence, some modern compilers, the effect of left-shifting a negative number may be worse than anything that could be caused by any kind of Undefined Behavior on a typical C99 compiler on platforms that separate code and data spaces and trap stack overflow. Even if code engaged in Undefined Behavior which could cause random control transfers, there would be no means by which it could cause arm_missiles()
and launch_missiles()
to be called consecutively without having an intervening call to disarm_missiles()
unless at least one call to should_launch_missiles()
returned a non-zero value. A hyper-modern compiler, however, may negate such protections.
No. Example:
struct T {
void f() { }
};
int main() {
T *t = nullptr;
if (t) {
t->f(); // UB if t == nullptr but since the code tested against that
}
}
Deciding whether a program will perform an integer division by 0 (which is UB) is in general equivalent the halting problem. There is no way a compiler can determine that, in general. And so the mere presence of possible UB can not logically affect the rest of the program: a requirement to that effect in the standard, would require each compiler vendor to provide a halting problem solver in the compiler.
Even simpler, the following program has UB only if the user inputs 0:
#include <iostream>
using namespace std;
auto main() -> int
{
int x;
if( cin >> x ) cout << 100/x << endl;
}
It would be absurd to maintain that this program in itself has UB.
Once the undefined behavior occurs, however, then anything can happen: the further execution of code in the program is then compromised (e.g. the stack might have been fouled up).