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:
movl $1, %eax
retint table[4] = {0};
int exists_in_table(int v)
{
// return true 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:
movl $1, %eax
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():
movl $11, %eax
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 (foo with gcc, bar with clang).
foo:
xorl %eax, %eax
ret
bar:
retqChoose 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;
int a=1,b=1,c=1;
// Endless loop with no side effects is UB
while (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.
| 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