When the C (or C++) standard says “doing X is undefined behavior”, they’re not telling you that your program will exit with an error, corrupt your memory, or even crash for that matter. These are only a few of ways in which undefined behavior can manifest.
There is a reason they are called “nasal demons”. In principle, undefined behavior could wipe your entire hard drive.
Of course, in the real world, compilers are too lazy to actually make your program erase the disk. Instead, they tend to take simpler route and assume that undefined behavior is “impossible”.
It doesn’t matter if it’s actually not impossible. The compilers don’t care. They want the most optimal code, and they will get the most optimal code even if it means wreaking havoc on your program.
Consider the following example:
#include <stdio.h>
int *getnumptr(int condition)
{
static int n = 42;
if (condition) {
return NULL;
}
return &n;
}
int main(int argc, char **argv)
{
int condition = argc - 1;
int num = *getnumptr(condition);
printf("%i\n", num);
return 0;
}
Suppose you don’t pass any arguments to this program (i.e. argc == 1
). In this case, the pointer returned by getnumptr
points to n
, which contains 42
, so you should expect 42
to be printed.
However, if you do pass arguments to the program (i.e. argc > 1
), then you’re in the realm of undefined behavior. On some compilers, the program will crash with a segmentation fault, which is probably what most people expect.
On less forgiving compilers however, the program may simply print 42
.
How could one get a 42
by dereferencing a NULL
pointer?
Well, the compiler was free to assume that the situation of dereferencing a NULL
pointer was “impossible”, and hence didn’t bother to emit the code for that case at all. The if
block was entirely elided from the generated assembly. All that remained was:
When they say undefined behavior means anything goes, they really mean it.
This article is brought to you by undefined behavior.
Show Disqus comments
comments powered by Disqus