Renders the entire program meaningless if certain rules of the language are violated.
The C++ standard precisely defines the observable behavior of every C++ program that does not fall into one of the following classes:
std::size_t
or the number of bits in a byte, or the text of std::bad_alloc::what
. A subset of implementation-defined behavior is locale-specific behavior, which depends on the implementation-supplied locale. 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(int): movl $1, %eax ret
int table[4] = {}; bool 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 true; } return false; }
May be compiled as (demo).
exists_in_table(int): movl $1, %eax ret
std::size_t f(int x) { std::size_t a; if(x) // either x nonzero or UB a = 42; return a; }
May be compiled as (demo).
f(int): mov eax, 42 ret
the output shown was observed on an older version of gcc.
bool p; // uninitialized local variable if(p) // UB access to uninitialized scalar std::puts("p is true"); if(!p) // UB access to uninitialized scalar std::puts("p is false");
Possible output:
p is true p is false
int f() { bool b = true; unsigned char* p = reinterpret_cast<unsigned char*>(&b); *p = 10; // reading from b is now UB return b == 0; }
May be compiled as (demo).
f(): movl $11, %eax ret
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 = nullptr; return *p; // Unconditional UB }
may be compiled as (foo with gcc, bar with clang).
foo(int*): xorl %eax, %eax ret bar(): retq
Choose clang to observe the output shown.
#include <iostream> #include <cstdlib> int main() { int *p = (int*)std::malloc(sizeof(int)); int *q = (int*)std::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 std::cout << *p << *q << '\n'; }
Possible output:
12
Choose clang to observe the output shown.
#include <iostream> 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() { if (fermat()) std::cout << "Fermat's Last Theorem has been disproved.\n"; else std::cout << "Fermat's Last Theorem has not been disproved.\n"; }
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.
http://en.cppreference.com/w/cpp/language/ub