-
if a splice results in a character sequence that matches the syntax of a universal-character-name, the behavior is undefined.
- [lex.phases]p1.2
- Example from Stack Overflow question:
const char* p = "\\ u0041";
-
If a character sequence that matches the syntax of a universal-character-name is produced by token concatenation (19.3.3), the behavior is undefined. [lex.phases]/p4
- [lex.phases]p1.4
- Examples:
#define GUARD_NAME ï ## _GUARD // UB per current spec #define COLUMN "ï" ## _column // UB per current spec
- A preprocessing token is the minimal lexical element of the language in translation phases 3 through 6. … If a ’ or a " character matches the last category, the behavior is undefined. [lex.pptoken]/p2
#define STR_START " #define STR_END " int puts(const char *); int main() { puts(STR_START hello world STR_END); }
- Examples live
- Discussion
- Rationale
- Preprocessing token are generated during phase 3 so string and character literals as well and header names are identified at this point. both ‘ and “ would only be valid as part of one of these tokens, any left over after this point perhaps as part of a macro would not be valid since they could not tokenized as needed anymore. Macros are expanded as part of phase 4.
- The effect of attempting to modify a string literal is undefined
- Examples:
const char *p1 = "hello world\n"; char *p2 = const_cast<char*>(p1) ; // const_cast is already suspicious p2[0] = 'm' ;
- Examples live
- Rationale *[lex.string]p8
Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration (6.6.4).
- There can be more than one definition of a class type (Clause 12), enumeration type (10.2), inline function with external linkage (10.1.6), inline variable with external linkage (10.1.6), class template (Clause 17), non-static function template (17.6.6), concept (17.6.8), static data member of a class template (17.6.1.3), member function of a class template (17.6.1.1), or template specialization for which some template parameters are not specified (17.8, 17.6.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then ... If the definitions of D do not satisfy these requirements, then the behavior is undefined.
-
Examples from: DCL60-CPP. Obey the one-definition rule
// a.cpp struct S { int a; }; // b.cpp // S in b.cpp does not consist of the same sequence of token as S in a.cpp class S { public: int a; };
const int n = 42; int g(const int &lhs, const int &rhs); inline int f(int k) { return g(k, n); // f() has external linkage // n has internal linkage but is our-used by g() // n will not be identical in all transition units }
-
Rationale:
- A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the
destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor,
the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released;
however, if there is no explicit call to the destructor or if a delete-expression ([expr.delete]) is not used to release the storage,
the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
- [basic.life]p5
- Pull request 2342 indicates this may not be undefined behavior at all and seeks the following edit
implicitly called and any program that depends on the side effects produced by the destructor has undefined behaviorimplicitly called.
- If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following
cases
- [basic.indet]p2
- Examples
int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true }
- Rationale
- WG14 Defect report 260
- WG14 Defect report 451
- Tl;DR; We have two case one in which using an indeterminate value is undefined behavior and this is because many type can have trap representations and using these value are undefined behavior. In the case of narrow character types the underlying values and type representation are one to one and therefore we don’t have a trap representation but they do retain their indeterminateness.
-
An implementation shall not predefine the main function. This function shall not be overloaded. Its type shall have C++ language linkage and it shall have a declared return type of type int, but otherwise its type is implementation-defined.
- [basic.start.main]p2
- Examples:
void main() {}
-
The function main shall not be used within a program
-
Examples:
- Is it illegal to take address of main() function?
- Why does gcc warn about decltype(main()) but not clang?
printf( “%p\n”, &main ) ; decltype(main()) x = 0;
int main() { std::cout << reinterpret_cast<void*>(&main) ; }
-
Tools
-
Rationale:
- From ARM section 3.4 Start and Termination
This is to ensure full freedom of the implementation of the interface between a C++ program and its environment. One could imagine an implementation where main() was not implemented as a function.
- [ub] What does "The function main shall not be used within a program" mean?
- From ARM section 3.4 Start and Termination
- Signed integer overflow/underflow is undefined behavior
- [expr.pre]
- Examples
int x1=std::numeric_limits<int>::max()+1; int x2=std::numeric_limits<int>::min()-1; int x3=std::numeric_limits<int>::min() / -1;
- Examples live 1 and examples live 2
- Converting floating point value to type that cannot represent the value is undefined behavior even for float
- [conv.double]p1
- Examples
double d2=DBL_MAX; float f=d2;
- examples live
- Converting floating point value to an integral that cannot represent the value is undefined behavior
- [conv.fpint]p1
- Examples
double d=(double)INT_MAX+1; int x=d;
- Calling a function through an expression whose function type is different from the function type of the called
function’s definition results in undefined behavior
- [expr.call]p6
- Examples
int f_c(int); using c1 = int(*)(int); using c2 = int(*)(int,int); int f(c2 func) { return func(1,2); } int main() { f(reinterpret_cast<c2>(f_c)); }
-
If the object of type “cv1 B” is actually a base class subobject of an object of type D, the result refers to the enclosing object of type D. Otherwise, the behavior is undefined.
- [expr.static.cast]
- Examples:
struct B {}; struct D1:B {}; struct D2:B {}; void f() { D1 d; B &b = d; static_cast<D2&>(b); }
-
Setting an enum to a value outside the range of enumerators is undefined behavior
- [expr.static.cast]p10 and [dcl.enum]p8
- Examples
enum A {e1=1, e2}; void f() { enum A a=static_cast<A>(4); }
-
Down-casting to the wrong derived type is undefined behavior
- [expr.static.cast]p11
- Examples
struct B {}; struct D1:B {}; struct D2:B {}; void f() { B* bp = new D1; static_cast<D2*>(bp); }
-
Using array delete on the result of a single object new expression and vice versa is undefined behavior
- [[expr.delete]p2])http://eel.is/c++draft/expr.delete#2)
- Examples
int *x = new int; delete [] x;
-
If the dynamic type differs from the static type of the object being deleted that is undefined behavior
- [expr.delete]p3
- Examples
int *p = new int; float *f = reinterpret_cast<float*>(p); delete f;
-
Deleting and incomplete type and the class turns out to have a non-trivial destructor is undefined behavior
- [expr.delete]p5
- Examples
struct A; void f(A *p) { delete p; } struct A {~A(){}};
-
If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined
- [expr.mptr.oper]p4
- Examples:
struct B{}; struct D:B{int x;}; void f(){ B *b= new B; D *d=static_cast<D*>(b); int D::* p=&D::x; (*d).*p=1; }
-
If the second operand is the null member pointer value (7.3.12), the behavior is undefined.
- [expr.mptr.oper]p6
- Examples:
struct S { int i; }; void f() { S cs; int S::* pm = nullptr; cs.*pm = 88; }
- Divison by zero is undefined behavior
- [expr.mul]p4
- Examples:
int x = 1/0; double d = 1.0/0.0;
-
Incrementing pointer beyond one past the end of an array is undefined behavior
- [expr.add]p4 and footnote
- Examples:
static const int arrs[10]{}; void f() { const int* y = arrs + 11; }
-
Subtracting pointers that are not part of the same array is undefined behavior
- [expr.add]p5.3
- Examples:
void f() { int x; int y; int *p1=&x; int *p2=&y; std::ptrdiff_t off = p1-p2; }
-
Shifting by a negative amount is undefined behavior
- [expr.shift]p1
- Examples
int y = 1 << -1;
-
Shifting by equal or greater than the bit-width of a type is undefined behavior
- [expr.shift]p1
- Examples:
int y1 = 1 << 32; int y2 = 1 >> 32;
-
Shifting a negative signed type is undefined behavior (before C++20)
- [expr.shift]p2
- Examples:
int y4 = -1 << 12;
- Overlap in an assignment expression must be exact and the objects must have the same type
- [expr.ass]p8
- Examples:
int x=1; char *c=reinterpret_cast<char*>(&x); x = *c;
- Flowing off the end of a value returning function is undefined behavior
- [stmt.return]p2
- Examples:
int f(int x) { if(x) return 1; } void b(){ int x=f(0); }
- Recursively entering declaration of a block scope static variable during initialization is undefined behavior
- [stmt.dcl]p4
- Examples:
int foo(int i) { static int s = foo(2*i); return i+1; }
-
Attempting to modify a const object is undefined behavior
- [dcl.type.cv]p4
- Examples:
int bar() { const int x=1; int *p = const_cast<int*>(&x); *p = 2; return *p; }
-
Accessing a volatile value through a non-volatile is undefined behavior
- [dcl.type.cv]p5
- Examples:
void f() { volatile int x=0; int &y=const_cast<int&>(x); std::cout << y; }
- In contracts side effects in a predicate to an object whose lifetime did not begin and end within the evaluation of the predicate are undefined behavior
- [dcl.attr.contract.syn]p6
- Examples:
int min = -42; constexpr int g(int x) { /* ... */ [[assert: ++min > 0]]; // undefined behavior /* ... */ return 0; }
- if a postcondition odr-uses a non-reference parameter in its predicate and the function body makes direct or indirect modifications of the value of that parameter, the behavior is undefined.
- [dcl.attr.contract.cond]p7
- Examples:
int f(int x) [[ensures r: r == x]] { return ++x; // UB }
- Violating a non-checked contract is undefined behavior outside of a constant expression context
- [dcl.attr.contract.check]p4
- Rationale see p1321r0 and p1490r0
- Examples:
void f(int x) [[expects audit: x>=1 && x<=2]]; void b() { f(100); }
- A function declared noreturn eventually returns it is undefined behavior
- [dcl.attr.noreturn]p2
- Examples:
[[ noreturn ]] void q(int i) { // behavior is undefined if called with an argument <= 0 if (i > 0) throw "positive"; }
- Calling a non-static member function of a class with an object that is not of that type is undefined behavior
- [class.mfct.non-static]p2
- Examples:
struct X { int x=1; int f() { return x;} }; struct A {int x=3;}; int f(X*x) { return x->f(); }
-
Explicit destructor call for an object not of the type is undefined behavior
- [class.dtor]p14
- Examples:
struct X {}; void f() { X *x=nullptr; x->~X(); }
-
Invoking the destructor for an object once its lifetime has ended is undefined behavior
- [class.dtor]p16
- Examples:
struct A{ ~A(){} }; int main() { A a; a.~A(); // Destructor will be invoked again at scope exit invoking UB }
- Accessing a non-active union member is undefined behavior
- [class.union]p1
- Examples:
union Y { float f; int k; }; void g() { Y y = { 1.0f }; // OK, y.f is active union member (10.3) int n = y.k; }
- Calling a virtual function from a constructor or destructor in an abstract class is undefined behavior
- [class.abstract]p6
- Examples:
struct B { virtual void f()=0; B() { f();} }; struct D : B{ void f() override { } };
- Calling a member function before all baes are initialized is undefined behavior
- [class.base.init]p16
- Examples:
struct B { B(int); }; struct D : public B { int f(); D() : B(f()) {} };
-
For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior
- [class.cdtor]p1
- Examples
struct W { int j; }; struct X : public virtual W { }; struct Y { int* p; X x; Y() : p(&x.j) { // undefined, x is not yet constructed } };
-
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior
- [class.cdtor]p3
- Examples:
struct A { }; struct B : virtual A { }; struct C : B { }; struct D : virtual A { D(A*); }; struct X { X(A*); }; struct E : C, D, X { E() : D(this), // undefined: upcast from E* to A* might use path E* ! D* ! A* // but D is not constructed // “D((C*)this)” would be defined: E* ! C* is defined because E() has started, // and C* ! A* is defined because C is fully constructed X(this) {} // defined: upon construction of X, C/B/D/A sublattice is fully constructed. };
-
To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
- [class.cdtor]p3
- Examples:
struct A { int x; }; void f() { A a; a.~A(); int *p=&a.x; // Destruction completed so computing the pointer is undefined behavior }
-
If the virtual function call uses an explicit class member access (7.6.1.4) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.
- [class.cdtor]p4
- Examples:
struct V { virtual void f(); virtual void g(); }; struct A : virtual V { virtual void f(); }; struct B : virtual V { virtual void g(); B(V*, A*); }; struct D : A, B { virtual void f(); virtual void g(); D() : B((A*)this, this) { } }; B::B(V* v, A* a) { f(); // calls V::f, not A::f g(); // calls B::g, not D::g v->g(); // v is base of B, the call is well-defined, calls B::g a->f(); // undefined behavior, a’s type not a base of B. }
-
If the operand of typeid refers to the object under construction or destruction and the static type of the operand is neither the constructor or destructor’s class nor one of its bases, the behavior is undefined
- [class.cdtor]p5
- Examples:
struct V { virtual void f(); }; struct A : virtual V { }; struct B : virtual V { B(V*, A*); }; struct D : A, B { D() : B((A*)this, this) { } }; B::B(V* v, A* a) { typeid(*this); // type_info for B. typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B typeid(*a); // undefined behavior: type A not a base of B dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B* dynamic_cast<B*>(a); // undefined behavior, a has type A*, A not a base of B }
-
If the operand of the dynamic_cast refers to the object under construction or destruction and the static type of the operand is not a pointer to or object of the constructor or destructor’s own class or one of its bases, the dynamic_cast results in undefined behavior
- [class.cdtor]p6
- Examples:
struct V { virtual void f(); }; struct A : virtual V { }; struct B : virtual V { B(V*, A*); }; struct D : A, B { D() : B((A*)this, this) { } }; B::B(V* v, A* a) { typeid(*this); // type_info for B. typeid(*v); // well-defined: *v has type V, a base of B yields type_info for B typeid(*a); // undefined behavior: type A not a base of B dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B* dynamic_cast<B*>(a); // undefined behavior, a has type A*, A not a base of B }