Undefined behavior

The C language standard precisely specifies the observable behavior of C language programs, except for the ones in the following categories:

(Note: Strictly conforming programs do not depend on any unspecified, undefined, or implementation-defined behavior)

The compilers are required to issue diagnostic messages (either errors or warnings) for any programs that violates any C syntax rule or semantic constraint, even if its behavior is specified as undefined or implementation-defined or if the compiler provides a language extension that allows it to accept such program. Diagnostics for undefined behavior are not otherwise required.

UB and optimization

Because correct C programs are free of undefined behavior, compilers may produce unexpected results when a program that actually has UB is compiled with optimization enabled:

For example,

Signed overflow

int foo(int x)
{
    return x + 1 > x; // either true or UB due to signed overflow
}

may be compiled as (demo)

foo:
        mov     eax, 1
        ret

Access out of bounds

int table[4] = {0};
int exists_in_table(int v)
{
    // return 1 in one of the first 4 iterations or UB due to out-of-bounds access
    for (int i = 0; i <= 4; i++)
        if (table[i] == v)
            return 1;
    return 0;
}

May be compiled as (demo)

exists_in_table:
        mov     eax, 1
        ret

Uninitialized scalar

_Bool p; // uninitialized local variable
if (p) // UB access to uninitialized scalar
    puts("p is true");
if (!p) // UB access to uninitialized scalar
    puts("p is false");

May produce the following output (observed with an older version of gcc):

p is true
p is false
size_t f(int x)
{
    size_t a;
    if (x) // either x nonzero or UB
        a = 42;
    return a;
}

May be compiled as (demo)

f:
        mov     eax, 42
        ret

Invalid scalar

int f(void)
{
    _Bool b = 0;
    unsigned char* p = (unsigned char*)&b;
    *p = 10;
    // reading from b is now UB
    return b == 0;
}

May be compiled as (demo)

f:
        mov     eax, 11
        ret

Null pointer dereference

int foo(int* p)
{
    int x = *p;
    if (!p)
        return x; // Either UB above or this branch is never taken
    else
        return 0;
}
 
int bar()
{
    int* p = NULL;
    return *p;    // Unconditional UB
}

may be compiled as (demo)

foo:
        xor     eax, eax
        ret
bar:
        ret

Access to pointer passed to realloc

Choose clang to observe the output shown

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    int *p = (int*)malloc(sizeof(int));
    int *q = (int*)realloc(p, sizeof(int));
    *p = 1; // UB access to a pointer that was passed to realloc
    *q = 2;
    if (p == q) // UB access to a pointer that was passed to realloc
        printf("%d%d\n", *p, *q);
}

Possible output:

12

Infinite loop without side-effects

Choose clang to observe the output shown

#include <stdio.h>
 
int fermat()
{
    const int MAX = 1000;
    // Endless loop with no side effects is UB
    for (int a = 1, b = 1, c = 1; 1;)
    {
        if (((a * a * a) == ((b * b * b) + (c * c * c))))
            return 1;
        ++a;
        if (a > MAX)
        {
            a = 1;
            ++b;
        }
        if (b > MAX)
        {
            b = 1;
            ++c;
        }
        if (c > MAX)
            c = 1;
    }
    return 0;
}
 
int main(void)
{
    if (fermat())
        puts("Fermat's Last Theorem has been disproved.");
    else
        puts("Fermat's Last Theorem has not been disproved.");
}

Possible output:

Fermat's Last Theorem has been disproved.

References

1. What Every C Programmer Should Know About Undefined Behavior #1/3
2. What Every C Programmer Should Know About Undefined Behavior #2/3
3. What Every C Programmer Should Know About Undefined Behavior #3/3
4. Undefined behavior can result in time travel (among other things, but time travel is the funkiest)
5. Understanding Integer Overflow in C/C++
6. Undefined Behavior and Fermat’s Last Theorem
7. Fun with NULL pointers, part 1 (local exploit in Linux 2.6.30 caused by UB due to null pointer dereference)

See also

C++ documentation for Undefined behavior

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/behavior