Undefined behavior - cppreference.com (original) (raw)

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.

Contents

[edit] 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,

[edit] Signed overflow

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

may be compiled as (demo)

[edit] 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

[edit] 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):

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

May be compiled as (demo)

[edit] 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)

[edit] 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

[edit] 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:

[edit] 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.

[edit] References

[edit] See also

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)