C99 defines undefined behavior in Section 3.4.3 as:
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
EXAMPLE An example of undefined behavior is the behavior on integer overflow.
C99 Section 4 explains how the standard identifies undefined behaviors:
If a "shall" or "shall not" requirement that appears outside of a constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words "undefined behavior" or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe "behavior that is undefined".
C99 Annex J.2, "Undefined behavior" contains a list of explicit undefined behaviors in C99.
Behavior can classified as undefined by the C standards committee for a variety of reasons including:
- The behavior is erroneous.
- The behavior is difficult to diagnose.
- As a hook for implementation extensions.
Conforming implementation cans deal with undefined behavior in a variety of fashions, from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Because compilers are not obligated to generate code for undefined behavior, these behaviors are ripe for optimization. By assuming that undefined behaviors will not occur, compilers can generate code with better performance characteristics.
Unfortunately, undefined behaviors can occur, particularly in the presence of an an attacker, making it more difficult to determine how these systems will behave. This is particularly true when examining the source code, because if the code relies on undefined behaviors, a code reviewer cannot be certain if the code will be compiled or if it will be compiled out. Furthermore, just because a compiler currently generates objects code for an undefined behavior, does not mean that future versions of the compiler are obligated to do the same; and this behavior may eventually be viewed as an opportunity for further optimization. Compilers are also not required to issue diagnostics for undefined behavior, so this code could simply be compiled out.
All of this puts the onerous on the programmer to write conforming applications, with or without the help of the compiler. Because performance is a primary emphasis of the C language, this situation is likely to get worse before it gets better.
Non-Compliant Coding Example
Post-condition checking for signed integer overflow.
Compliant Solution
Pre-condition checking for signed integer overflow.