Undefined Behavior¶
A programming-language case for which the governing specification imposes no requirements on implementation behavior.
Core Idea¶
In a programming-language specification, undefined behavior (UB) is behavior for which the governing document imposes no requirements on a conforming implementation. The cited C++ working draft uses exactly that contract category. For an operation classified as UB under a particular language version, the standard does not promise a wrapping result, exception, diagnostic, crash or any other specific result simply because that operation is reached. A compiler can also reason about executions in which the prohibited condition never arises; transformations valid for those defined executions need not preserve a programmer's hoped-for behavior in an undefined case.[1][2][3]
The standard and version are part of the identity. A signed arithmetic result outside its type's representable range is undefined under the cited C++ draft. So is a negative shift count or a shift count at least the width of the promoted left operand. Other languages and intermediate representations may classify operations differently. The frozen seed's processor-manual “UNPREDICTABLE” example is not silently merged into this language-standard category.[4][5]
Structural Signature¶
Sig role-phrases:
- Governing specification — A named language and version states which program executions have required semantics. Without it, “undefined” is ambiguous.[1]
- Triggered undefined condition — An operation or construct falls under a no-requirements clause, such as the cited signed overflow or invalid shift count. Code that never reaches that condition is not made undefined merely by containing a branch with it.[4][5]
- Implementation contract gap — The specification supplies no mandated outcome for that case, unlike categories with allowed or documented alternatives.[1][2]
- Defined-execution invariant — Correctness claims and permitted compiler transformations are evaluated against executions satisfying language preconditions; observed post-trigger results are not portable guarantees.[3]
- Diagnostic boundary — A compiler may warn or a sanitizer may flag a case, but detection is separate from the normative classification; absence of a warning does not prove defined behavior.[1][6]
Condensed: versioned specification → identified undefined condition → no required implementation outcome for that case → defined-execution reasoning, not outcome prediction.
What It Is Not¶
- Not unspecified behavior. A specification may allow a bounded choice among outcomes without requiring documentation; that is still a constrained category, not UB.[2]
- Not implementation-defined behavior. Here the implementation must document its chosen behavior; UB imposes no corresponding requirement.[2]
- Not the recent C++ draft's erroneous behavior. That category is well-defined behavior recommended for diagnosis, even though it results from incorrect code. “Erroneous program” is therefore not an alias for UB.[7]
- Not necessarily a visible crash. A program may seem to work in one build or input despite a UB event; such an observation is not a standards guarantee.[1]
- Not every overflow. Ordinary unsigned arithmetic wrap has defined modulo behavior in C++ and must not be inferred to be the same as unrepresentable signed arithmetic.[3]
Scope of Application¶
The entry concerns the normative behavior categories of programming-language specifications, illustrated mainly by the cited C++ working draft. The same broad notion appears in C and compiler intermediate representations, but their detailed rules differ. LLVM IR, for example, distinguishes immediate from deferred undefined behavior and models poison values in ways not reducible to one C++ source-level slogan. The language and abstraction level must be declared before moving a UB claim from source code to IR or machine instructions.[8][1]
The C++ draft's abstract-machine language also cautions against an unqualified “anything can happen before and after” slogan. Its current wording defines an observable prefix around checkpoints and permits arbitrary additional observable behavior after an undefined operation in the selected execution. This qualification is versioned: promotion should record the exact draft snapshot instead of treating a moving working draft as timeless law.[2]
Clarity¶
The central distinction is between unconstrained by the specification and unknown to the programmer. A program may have an implementation-defined result that the programmer has not looked up; it is still governed and documented. A compiler may choose one of several unspecified outcomes without documenting which; it is still bounded by the standard's set. UB is the stronger absence of requirements for the relevant case.[1][2]
Nor is “incorrect” identical to “undefined.” The latest cited C++ draft explicitly gives erroneous behavior a well-defined status while recommending diagnosis. This is why the other frozen title, Erroneous Program, remains a separate identity-review hold.[7]
Manages Complexity¶
A language standard cannot or does not want to prescribe every corner-case result. UB marks conditions outside its mandated behavior, allowing implementations to use assumptions about defined executions and avoid some checks or constraints. LLVM's compiler explanation uses signed overflow to show how a compiler can simplify x+1>x when overflowing signed addition is outside the defined case.[3][4]
The compact contract category also shifts a burden to authors and tools: they must establish preconditions such as valid ranges before relying on an expression's result. A sanitizer can detect selected violations dynamically, but its checks are incomplete relative to every possible language-semantic issue and instrumented runtime behavior is not the definition itself.[6]
Abstract Reasoning¶
Start by naming the language, version and exact rule. Ask whether an execution reaches the operation under the rule's triggering conditions. If not, ordinary specified semantics apply. If yes, do not infer a portable outcome from a test run or a particular assembly listing. Analyze the program under defined-input preconditions, add checks or change representation if the condition must be handled, and retest; diagnostic tools can assist but cannot replace the standards argument.[1][6]
For signed integers, if x could equal the maximum representable value, x+1 would overflow under the cited draft. A compiler may optimize a comparison for executions where that does not happen. For shifts, a count equal to the promoted left operand's width triggers a separate explicit UB clause. By contrast, ordinary unsigned wrap is a boundary counterexample: it has a specified result rather than a missing contract.[4][5][3]
Knowledge Transfer¶
The question “what does the governing specification require here?” transfers between C, C++, compiler IRs and hardware specifications. The answer does not transfer without checking each version's terminology and rules. LLVM IR's poison model is not simply source-level C++ UB, and an ISA's UNPREDICTABLE category may impose a different contract.[8]
UB's broad no-requirements shape resembles Underspecification, but the named abstraction has a specific normative programming-language role. That is not enough to claim prime status or attach a strict parent without comparing the live definitions.
Examples¶
Unrepresentable signed arithmetic result¶
In the cited C++ draft, evaluating a signed arithmetic expression whose mathematical result is outside its type's representable range is UB. For x at the signed maximum, x+1 meets that condition. A compiler can simplify expressions on the assumption that defined signed executions do not overflow; the observed wraparound of one binary would not establish a portable rule.[4][3]
Mapped back: specification = cited C++ draft; condition = out-of-range signed result; contract gap = no required overflow value; invariant = reason only on nonoverflowing executions; diagnostic = a sanitizer may flag the reached case.
Shift count outside the permitted range¶
The C++ draft states that a shift expression has UB when its right operand is negative or at least the width of the promoted left operand. Thus a count equal to the width is outside the specified operation even if a particular processor masks the count or appears to produce a repeatable result.[5]
Mapped back: specification = C++ [expr.shift]; condition = too-wide count; contract gap = no required shifted value; invariant = ensure count lies within range in defined executions; diagnostic = instrumentation may detect the violation.
Near miss: unsigned wrap¶
Unsigned addition exceeds its maximum and wraps modulo its range under ordinary C++ arithmetic rules. It may be surprising to a programmer, but the standard specifies the result. This is not the cited signed-overflow UB case.[3]
Structural Tensions¶
Optimization latitude versus programmer predictability. Leaving some conditions without requirements lets a compiler optimize defined executions aggressively but makes accidentally reached cases nonportable. Defining every corner case would constrain some transformations or require handling costs; relying on unmandated outcomes creates fragile software. Diagnostic: which exact standard precondition underwrites the desired optimization or result, and can the program prove it holds?[3][1]
Memorable warning versus normative precision. “Anything can happen” discourages dangerous reliance, yet recent C++ wording specifies a defined observable prefix and distinguishes erroneous behavior. Overbroad rhetoric can obscure verification; overreading the prefix can invite false post-UB assumptions. Diagnostic: what does the versioned abstract-machine clause require before the undefined operation, and what remains unconstrained afterward?[2][7]
Structural–Framed Character¶
UB has a crisp no-requirements relation but is standards-framed. Its vocabulary travels among programming languages and IRs only when each governing specification defines a comparable category; applying the name to ordinary uncertainty imports a language-contract assumption. It depends on human standard-setting and compiler implementation, with formal semantic consequences; standards bodies institutionalize the category. Its evaluative weight is indirect: the clause is normative about implementation obligations, while calling code “bad” is a separate engineering judgment. The generic skeleton of a missing guarantee may relate to Underspecification, but it does not grant this language-specific node prime status. Its character: structurally precise as a contract gap, substantially framed by programming-language standards and versions.
Structural Core vs. Domain Accent¶
The skeleton is that a governing specification places no requirement on one case. The domain mechanism is a programming-language abstract machine in which source constructs, runtime conditions, compiler optimizations and observable executions interact. Without a versioned language rule, this becomes generic underspecification; without a no-requirements clause, it may be unspecified, implementation-defined or erroneous behavior instead. The named entry does not clear the prime bar because its consequences and boundary depend on programming-language contracts. Any generic portability belongs to a broader candidate, not automatically to this node.
Instantiates / Related Primes¶
Underspecification and Constraint are related primes, but neither has been shown to subsume the normative category of undefined behavior. Type Error is a different failure mode that may or may not be diagnosed; it is not a synonym for undefined behavior. Erroneous behavior in recent C++ is a separate notion: it is well-defined, not undefined.
Neighborhood in Abstraction Space¶
Undefined Behavior sits in a sparse region of the domain-specific corpus (88th percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely.
Family — Program Scope & Nesting Disciplines (10 abstractions)
Nearest neighbors
- Proof of correctness — 0.83
- Proof-Carrying Code — 0.81
- Closure (programming) — 0.80
- Principle of Explosion — 0.80
- Contingent Contract — 0.79
Computed from structural-signature embeddings · 2026-10-08
Not to Be Confused With¶
Do not treat UB as a synonym for any bug, a crash, implementation-defined behavior or nondeterminism among allowed outcomes. Do not treat the C++ erroneous-behavior term or an ISA's UNPREDICTABLE term as automatic aliases. An optimizer's use of a UB rule is a consequence of the contract for defined executions; it is not evidence that every particular compiler must perform the same transformation.[1][7][3]
References¶
[1] C++ standards draft editors, “C++ Working Draft Eelis Snapshot c7015b485cc3db8efaa9dfb9ff0809c5394a4ed1”, unofficial eel.is HTML rendering of “Working Draft: Programming Languages — C++” generated 2026-08-23, [defns.undefined] no-requirements definition; not an ISO publication. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h ↩i ↩j
[2] C++ standards draft editors, “C++ Working Draft Eelis Snapshot c7015b485cc3db8efaa9dfb9ff0809c5394a4ed1”, unofficial eel.is HTML rendering of “Working Draft: Programming Languages — C++” generated 2026-08-23, [intro.abstract] unspecified/implementation-defined distinctions and defined-prefix wording; not an ISO publication. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g
[3] LLVM Project Blog, “What Every C Programmer Should Know About Undefined Behavior”, first-party optimization explanation. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h ↩i
[4] C++ standards draft editors, “C++ Working Draft Eelis Snapshot c7015b485cc3db8efaa9dfb9ff0809c5394a4ed1”, unofficial eel.is HTML rendering of “Working Draft: Programming Languages — C++” generated 2026-08-23, [expr.pre] unrepresentable arithmetic result; not an ISO publication. registry ↩a ↩b ↩c ↩d ↩e
[5] C++ standards draft editors, “C++ Working Draft Eelis Snapshot c7015b485cc3db8efaa9dfb9ff0809c5394a4ed1”, unofficial eel.is HTML rendering of “Working Draft: Programming Languages — C++” generated 2026-08-23, [expr.shift] negative or too-wide shift count; not an ISO publication. registry ↩a ↩b ↩c ↩d
[6] Clang, “UndefinedBehaviorSanitizer”, instrumented checks. registry ↩a ↩b ↩c
[7] C++ standards draft editors, “C++ Working Draft Eelis Snapshot c7015b485cc3db8efaa9dfb9ff0809c5394a4ed1”, unofficial eel.is HTML rendering of “Working Draft: Programming Languages — C++” generated 2026-08-23, [defns.erroneous] distinct well-defined erroneous behavior; not an ISO publication. registry ↩a ↩b ↩c ↩d
[8] LLVM, “LLVM IR Undefined Behavior Manual”, immediate/deferred IR semantics. registry ↩a ↩b