The C language standard precisely specifies the observable behavior of C language programs, except for the ones in the following categories:
islower returns true for any character other than the 26 lowercase Latin letters. (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.
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,
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
retint 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_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
retint 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
retint 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:
retrealloc
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
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.
| 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) |
| 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